4

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?

6
  • 2
    Name some specific other thing you want to use for a default. Then think through what that would demand of the compiler. Commented Nov 1, 2019 at 19:24
  • 3
    Because that's the way they made it. Commented Nov 1, 2019 at 19:25
  • 1
    My 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. Commented Nov 1, 2019 at 19:34
  • 1
    C# has always supported applying arbitrary defaults. It's called method overloading. Commented Nov 1, 2019 at 19:55
  • 1
    @KazemJavadi This answer may help you: Why optional parameter must be specified Commented Nov 2, 2019 at 19:25

2 Answers 2

5

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".

Sign up to request clarification or add additional context in comments.

3 Comments

Thank 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?
@KazemJavadi damn, you are right. I amended my answer with one more paragraph, I hope it makes things more clear now.
@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.
1

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); } 

Comments