What's the idea behind allowing private constant to be used as default parameters for public methods?
Asked Answered
R

4

5

To my surprise, this one compiles and runs:

class Program
{
    static void Main()
    {
        DoSomething();
    }

    private const int DefaultValue = 2; // <-- Here, private.

    public static void DoSomething(int value = DefaultValue)
    {
        Console.WriteLine(value);
    }
}

The method is public whereas the default value "redirects" to a constant private variable.

My question:

What is/was the idea behind this "concept"?

My understanding (until today) was, that something public can only be used if all other "referenced" elements are also public.

Update:

I just ILSpy-decompiled my class to find:

static class Program
{
    private static void Main()
    {
        Program.DoSomething(2);
    }

    private const int DefaultValue = 2;

    public static void DoSomething(int value = 2)
    {
        Console.WriteLine(value);
    }
}

So if the private constant as a default parameter is being done in e.g. a library, the user of the library still sees the default parameter.

Roydd answered 22/12, 2015 at 12:47 Comment(2)
Try putting in other uses of DefaultValue in the code (or indeed a public const) and you'll see that similarly the compiled code would just have a 2 there rather than a reference to DefaultValue.Sledge
These names are for people so DefaultValue should have a better name to be more descriptive of the intent like GiraffeHornCountDefaultValueStalinsk
S
5

The name DefaultValue is private, but the number 2 is still the number 2.

Because DefaultValue is private, we cannot access Program.DefaultValue from outside of Program. Presumably we wouldn't particularly want to.

And because we've bothered to define DefaultValue at all, it's presumably something that we do care about when we are working on how Program works.

So when we come to define a default value for DoSomething there's presumably some logical reason why the value we want there happens to be the same as the value DefaultValue.

And as such, it's presumably beneficial to be able to use that constant there, for much the same reasons as we would find constants beneficial anywhere.

And since DefaultValue is just a Program-specific way of saying 2, there's no real reason why we can't.

Of course, the metadata would reflect this as 2 rather than the (meaningless to the outside) DefaultValue, but then that would hold if the const was public anyway (the metadata about default values gives only the value, not whether or not it related to any defined constants).

So there's no downside.

So considering that:

  1. There's an advantage to the implementer.
  2. There's no disadvantage to the user, over just a use of a literal 2.
  3. Preventing it would have to introduce a special rule to be an exception to the rule that defined constants can be used anywhere a constant value from a literal can.

Why not?

Sledge answered 22/12, 2015 at 12:59 Comment(3)
I have not tested it but if this is done in a library, I probably will not see that this is a default parameter?!?Roydd
You'd see that it was a default parameter, but only that that default parameter was 2, not that it related to DefaultValue. This would hold even if DefaultValue was public. The produced CIL has .param [1] = int32(2) and it's not valid CIL to put a reference to a field, which is how DefaultValue is made visible to other code (the assembly contains .field public static literal int32 DefaultValue = int32(2) but any compilation that uses it will compile that use as 2 not as a ldfld instruction).Sledge
I see and just tried it. Thanks a lot for your help!Roydd
A
9

What is/was the idea behind this "concept"?

The idea is that as const value is static and never changes - you can use it as default value for method's optional parameters same as you can use normal values. A quote from MSDN :

Each optional parameter has a default value as part of its definition. If no argument is sent for that parameter, the default value is used. A default value must be one of the following types of expressions:

  • a constant expression;

  • an expression of the form new ValType(), where ValType is a value type, such as an enum or a struct;

  • an expression of the form default(ValType), where ValType is a value type.


My understanding (until today) was, that something public can only be used if all other "referenced" elements are also public

Well technically speaking it's correct. But in your scenario both members are accessible as they are defined in the same class however should const in our case be defined outside of class Program it'd be inaccessible inside class Program.

Asta answered 22/12, 2015 at 12:51 Comment(0)
S
5

When you use const, the compiler replaces all the occurrences of the variable with the actual value ,so your code is the same as this:

public static void DoSomething(int value = 2)
Stative answered 22/12, 2015 at 12:50 Comment(2)
Ofcourse @Fajan's answer really answers your question,the fact that the variable is const is irrelevant...Stative
It still matters that it’s a constant, because you can only use constant values as default argument values.Cissoid
C
5

Constant variables are replaced at compile-time, so they never really exist in the produced assembly. So code using a constant is really identical to just using the constant value directly. The benefit is just that you can reuse the constant elsewhere and only need to change it in one location.

Now, since constants are always replaced at compile-time, the effect of making them public or private is also quite simple: It just affects what other type can access it at compile-time. So using a private constant for example can be helpful if you just want to keep that constant to the current type, whereas a public constant can be used across the whole application.

Cissoid answered 22/12, 2015 at 12:53 Comment(1)
Thanks a lot for your answer!Roydd
S
5

The name DefaultValue is private, but the number 2 is still the number 2.

Because DefaultValue is private, we cannot access Program.DefaultValue from outside of Program. Presumably we wouldn't particularly want to.

And because we've bothered to define DefaultValue at all, it's presumably something that we do care about when we are working on how Program works.

So when we come to define a default value for DoSomething there's presumably some logical reason why the value we want there happens to be the same as the value DefaultValue.

And as such, it's presumably beneficial to be able to use that constant there, for much the same reasons as we would find constants beneficial anywhere.

And since DefaultValue is just a Program-specific way of saying 2, there's no real reason why we can't.

Of course, the metadata would reflect this as 2 rather than the (meaningless to the outside) DefaultValue, but then that would hold if the const was public anyway (the metadata about default values gives only the value, not whether or not it related to any defined constants).

So there's no downside.

So considering that:

  1. There's an advantage to the implementer.
  2. There's no disadvantage to the user, over just a use of a literal 2.
  3. Preventing it would have to introduce a special rule to be an exception to the rule that defined constants can be used anywhere a constant value from a literal can.

Why not?

Sledge answered 22/12, 2015 at 12:59 Comment(3)
I have not tested it but if this is done in a library, I probably will not see that this is a default parameter?!?Roydd
You'd see that it was a default parameter, but only that that default parameter was 2, not that it related to DefaultValue. This would hold even if DefaultValue was public. The produced CIL has .param [1] = int32(2) and it's not valid CIL to put a reference to a field, which is how DefaultValue is made visible to other code (the assembly contains .field public static literal int32 DefaultValue = int32(2) but any compilation that uses it will compile that use as 2 not as a ldfld instruction).Sledge
I see and just tried it. Thanks a lot for your help!Roydd

© 2022 - 2024 — McMap. All rights reserved.