I know that the default value of an optional parameter must be specified by a constant expression or a parameterless constructor of a value type. But I don't know why! Why we cannot use anything else? Can anyone explain the reason for me?
-
2Name some specific other thing you want to use for a default. Then think through what that would demand of the compiler. – 15ee8f99-57ff-4f92-890c-b56153 Nov 01 '19 at 19:24
-
3Because that's the way they made it. – rory.ap Nov 01 '19 at 19:25
-
1My best *guess* is that it has to do with the implementation: default values for parameters are substituted at the call site if not specified. And presumably constant values, null, and bytes-all-zero of a value type are easy to substitute, and more complex expressions are harder / more expensive than it's worth supporting by the compiler team. – Joe Sewell Nov 01 '19 at 19:34
-
1C# has always supported applying arbitrary defaults. It's called method overloading. – madreflection Nov 01 '19 at 19:55
-
Optional parameters is not a feature of the CLR. It has to be implemented by the compiler, when it sees a method call that relies on the default then it has to dig up the default value from the assembly metadata so it can compile the call. So necessarily that value cannot be computed by code, it has to be a "compile-time constant expression". Same rules as a [const declaration](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const). – Hans Passant Nov 02 '19 at 15:10
-
1@KazemJavadi This answer may help you: [Why optional parameter must be specified](http://www.ordisoftware.com/files/stack-overflow/Why-optional-parameter-must-be-specified.htm) – Nov 02 '19 at 19:25
2 Answers
The creators of C# decided that optional method arguments should not complicate the binary interface of classes, meaning that they should be a source-code-only, syntactic-sugar feature, making use of whatever other mechanisms pre-existed in the language, without adding anything new.
What this means is that for one thing, the default value expression for a given method argument must be fully resolvable at the time that each call to the method is being compiled.
But this requirement should still not prevent you from being able to instantiate a class to pass as a default value to an argument, if the class is known. So, the reality is a bit more complex than that.
In languages like C#, it is always possible to program against an assembly when you only have the DLL in your hands, without the source code. So, a "source-code-only" feature is never exactly source-code-only. In order to add optional method arguments to the language, they had to introduce a little trick: in the definition of a method, for each optional argument the compiler emits a certain attribute, the content of which specifies what the default value of the argument should be. This attribute is not used at runtime, it is used only at compilation time. So, when you are writing a call to that method, and you omit an optional argument, the compiler looks up the optional argument attribute in the target assembly, and knows what value it should pass.
However, attributes in C# also have this restriction: all of their parameters must be compile-time constants. (See ECMA-335 Partition II §21 "Custom attributes" and Partition II §23.3 "Custom attributes".)
So, ultimately, the answer to the question of why default argument values must be compile-time constants is because their implementation involves the use of attributes behind the scenes, and attribute arguments must in turn be compile-time constants.
The technical explanation of why attribute arguments must be compile-time constants is basically because the creators of the language did not want to make things too complicated. Attribute arguments must be so simple that they can be turned into an array of bytes and placed in the binary, and also when loading the class, this array of bytes must be very easily convertible to a set of arguments to pass to the attribute. For what it's worth, the exact same holds true for Java, where "attributes" are called "annotations".

- 56,297
- 11
- 110
- 142
-
1Thank you for your answer. But this is answer doesn't explain why for example we can not use an object of a class as a default parameter's value. Why compiler can not substitute that object in the caller point like a constant expression? Where is the problem? What would happen if the compiler does this? – Nov 02 '19 at 15:00
-
@KazemJavadi damn, you are right. I amended my answer with one more paragraph, I hope it makes things more clear now. – Mike Nakis Nov 02 '19 at 15:13
-
@KazemJavadi actually, I was dissatisfied with my answer, so I went ahead and I practically re-wrote it. I hope things are a lot more clear now. – Mike Nakis Nov 02 '19 at 15:57
This is not entirely true though. It is possible to define using ConstantAttribues. Jon Skeet wrote a nice blogpost about it.
Eseentially you can also do the following:
public void PrintDateTime([Optional, DateTimeConstant(635443315962469079L)] DateTime date)
{
Console.WriteLine(date);
}

- 9,195
- 4
- 44
- 71