Thoughts on C# 4.0’ optional parameters

C# 4.0 is just round the corner and along with it set of nice new additions to the language, including optional parameters. There’s been some historical resistance to add this feature to the language, but here' it is, and I’m glad it’s coming, or at least I was.

In few words, optional parameters, have their default value specified in the signature of the method. You can then skip them when calling method, and the method will be called with their default values.

So, what’s the deal?

To simplify the current discussion I will refer to the method containing default parameters (Foo in this example) as called method, and to method providing the default value (DateTime.Now getter in the example few paragraphs below) as value provider.

Take a look at the code below. Method Foo has two parameters, but we can call them as if it had none.

defaultParameters_0

Looking good so far, right? Let’s take a look at how Main method looks like in Reflector.

defaultArguments_1

As we can see there’s no magic here – simple compiler trick. Compiler binds the invocation to the method, and them puts the arguments for you. The code looks as if you had written it yourself in earlier version of C#.

Still good, right? So how does exactly the compiler knows what to put on the calling side? Let’s take a look at the compiled signature of the method Foo.

defaultParameters_2

Ha! The values are encoded in DefaultParameterValueAttribute. Do you see the problem here? No? Than let’s try something else. Let’s change the signature of the method to take DateTime instead of int.

defaultParameters_3

Notice we initialize the time to default value of DateTime.Now. All good? So let’s compile the code, shall we?

defaultParameters_4

Oops.

Turns out we can’t. What seems like a really reasonable code is not allowed. Since the default values for arguments are being kept in attributes they must be a compile time constants, which includes primitive types (numeric types and strings), tokens ( typeof, methodof, which is not exposed in C# though ) and nulls. Pretty disappointing right?  This means no new Foo(), no Foo.Bar is allowed. This dramatically limits the range of scenarios where this feature can be used, as most of the time, you’ll want not null, but something else as your default value, in which case you’ll end up creating overloads anyway.

There are some workarounds, like the one described in this book, but they have their own downsides, and it’s not always possible to use them anyway.

This all makes me think – why did the authors of the language decided to provide such crippled implementation of the feature? I’m not an expert in this matter, but I found a simple way in which the feature could be implemented allowing for far greater range of scenarios.

What if…

Let’s re-examine how this feature works.

  • The compiler puts the default values of the arguments in a special attribute type on the called method signature.
  • On the calling side, the compiler reads the values, and puts these of them that were not provided explicitly.

All the work happens at compile time (let’s ignore the dynamic for a moment, we’ll get to that as well) so no additional work at runtime is required. Since the compiler is very powerful, why not go one step further.

I think by simply extending this approach the following scenarios could be enabled.

  • using value returned by static parameterless method (this includes static property getters) as default value.
  • using value returned by instance parameterless method defined on the same type (or base type of the type) as called method is defined on (this would only be applicable for instance methods).
  • using default, parameterless constructors as default value.
  • or if we wanted to extend it further: using value returning by any variant of the above that does take parameters that are allowed to be put in the attribute (including both constants, and values of other parameters).

Let us examine how this could be (I think) achieved.

The spoon does not exist

What we would need is a way to store information which method, or constructor of which type we want to invoke in case no default value is provided. Since tokens are legal in attributes, the existing approach could be extended with something like this:

defaultParameters_5 

We have a way of storing the method. Now, the compiler could easily retrieve the token and invoke the called method.

  • If value provider is static there’s no problem – just call it, regardless of whether called method is an instance or static method.
  • If value provider is instance method, and called method is instance method as well, invoke the value provider on the instance on which called method is being invoked (hence the requirement that value provider must be declared on the same type as called method or its base type).
  • If value provider is instance method but called method is static do not allow (at compile time!) this code to compile, since there’s no instance to call the value provider on.

When it comes to constructors it is even simpler – since we allow only default constructor, at compile time we would check if the type does indeed have default, accessible constructor, and disallow the code to compile otherwise. Then when the called method is being invoked, retrieve the type token and call the default constructor on that type.

What about dynamic code?

I don’t have very intimate knowledge of dynamic code yet, but I think this could work with dynamic code as well. The compiler would put all the information on the call site (new concept introduced in .NET 4.0) and this would be all we need. In C# 1.0 having MethodInfo of a method you could invoke it. Same having System.Type it is easy to find and invoke it’s default constructor using little bit of reflection. I really see no reason why this would not work.

 

What do you think – am I missing part of the picture – is it something terribly wrong with my idea that would restrain it from working? Or maybe C# team didn’t really want (as they used to) implement this feature so they provided only the minimal implementation they needed for other major features, COM interop specifically.


Posted 09-03-2009 3:00 AM by Krzysztof Koźmic
Filed under:

[Advertisement]

Comments

Ollie Riches wrote re: Thoughts on C# 4.0’ optional parameters
on 09-03-2009 4:29 AM

I think the language has firmly entered the realms of 'feature envy'. I can't see my self using this much and I agree with you if you were going to use it I would want to be able to be 'dynamic' about the default values.

I think i'll put it on the 'avoid' pile with extension methods ;)

DotNetShoutout wrote Thoughts on C# 4.0’ optional parameters - Krzysztof Kozmic - Devlicio.us
on 09-03-2009 7:23 AM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Java Developer wrote re: Thoughts on C# 4.0’ optional parameters
on 09-03-2009 11:27 AM

Ollie hit the nail by saying "C# entered the realms of 'feature envy'"

Why keep adding extra load of ambiguous(rarely used) features to the language? Just to look better in comparison to other languages?

I'm staying with Java for over 10 years now... and pretty happy with it...

WebDevHobo wrote re: Thoughts on C# 4.0’ optional parameters
on 09-03-2009 11:50 AM

As far as my limited experience goes, optional parameters are better suited for procedural programming languages.

I agree with the other commenters, though calling it feature envy is only part of the story I think. C# wants to survive.

Remember Firefox 1.5? Back in the days that IE6 was still king of the internet?

Firefox had tabs... users wanted that and they started to leave IE6. Why did they leave? Because IE6 had no tabs.

So Microsoft included support for tabs in IE7, which was the major reason for the version update.

Whether seasoned programmer like this feature or not, the new programmers fresh out of college will like it. And they are the majority. And if Microsoft doesn't accommodate to their wishes, perceived or real, C# will be deserted for other languages that have these "cool" features.

And at that point, Microsoft will have 2 choices. Either forbidding those languages from running on windows, or shutting down C# all together.

Since Microsoft can't afford to do either, they adapt.

danderson00 wrote re: Thoughts on C# 4.0’ optional parameters
on 09-03-2009 11:57 AM

While I agree that this seems to be a somewhat limited implementation of optional parameters, I disagree with Ollie that this is 'feature envy'. It's primary purpose is to reduce the number of function overloads required in a lot of cases.

Joel Coehoorn wrote re: Thoughts on C# 4.0’ optional parameters
on 09-03-2009 12:47 PM

What's to stop you from just adding an initialization clause to the top of the method:

if (MyOptFooParam == null) MyOptFooParam = new Foo();

This is even better, because it allows you to change default values for a method in one assembly and have those default values **propogate** to calling code in another assembly without needing to re-compile that assembly.

Krzysztof Koźmic wrote re: Thoughts on C# 4.0’ optional parameters
on 09-04-2009 2:38 AM

@Joel

Two issues:

- first, the signature is somewhat lyingabout the default value, as it then is not null, but something else, which may be misleading

- two, for value types I'd have to use its nullable type which is a no-no.

Jon Skeet proposed similar solution to this in his book.

Tormod wrote re: Thoughts on C# 4.0’ optional parameters
on 09-04-2009 9:47 AM

When you find that the C# produced by the syntactic sugar is something that you would decide against writing yourself.... then it is not worth it. Explicit or implicit doesn't matter. It's my code.

Thank you for making me aware of this.

Casper Bang wrote re: Thoughts on C# 4.0’ optional parameters
on 09-04-2009 9:55 AM

Interesting entry, I had no idea C# had started to cut corners like that.

> I'm staying with Java for over 10 years now... and pretty happy with it...

Heh Java started cutting corners a very long time ago. Let me name a few: No decimal literal, pseudo properties, mangled generics, convoluted wildcards etc. It's ironic that what's keeping Java somewhat standing these days, is the annotation feature they borrowed from C#. That same feature is now the center of trying to work around Java's limitations i.e: http://projectlombok.org/

Casper Bang wrote re: Thoughts on C# 4.0’ optional parameters
on 09-04-2009 11:11 AM

- first, the signature is somewhat lyingabout the default value, as it then is not null, but something else, which may be misleading

But then how about doing both? Let the attribute handle the meta-data aspect, but also add an initialization line at the top of the method. I believe this is similar to how generics (by erasure) is implemented in Java. The generic type isn't truly there, but you can still reflect on it as it uses the meta-data.

- two, for value types I'd have to use its nullable type which is a no-no.

Would you mind explaining that one a bit better? Why would it have to be nullable?

Marcel wrote re: Thoughts on C# 4.0’ optional parameters
on 09-04-2009 3:19 PM

You know, the feature was added to keep the language in sync with VB, and the same limitation applies to VB (for ages).

invalid:

Sub DoStuff(Optional ByVal myString = String.Empty)

valid:

Sub DoStuff(Optional ByVal myString = "")

It really sucks.

Krzysztof Koźmic wrote re: Thoughts on C# 4.0’ optional parameters
on 09-05-2009 2:07 AM

Casper

Say you have a method:

bool CanDriveACar(DateTime born=DateTime.Now.Substract(TimeSpan.FromYears(18)))

DateTime is a value type, so you would not be able to use null as default value. You could use DateTime.MinValue, but it can be a valid value in your domain! How would you discriminate whether user wants DateTime.Min, passed explicitly,  or didn't pass the value so that you assign whatever your default value is.

Then, you'd have to use nullable type of DateTime - null, as default, and non-null as normal value.

But, then your implementation details leak to the signature of the method. When you're a user of that method, what would you think having method with born-date parameter that can be null?

Alwin wrote re: Thoughts on C# 4.0’ optional parameters
on 09-08-2009 8:49 PM

Krzysztof, what would you think of having a method with born-date (BTW I think it's called Date of Birth, DOB) parameter that you don't have to specify at all?

I mean, whether you pass DOB in as null, or you don't specify the DOB at all, both have the same result: the method CanDriveACar uses the default value. Which IMO doesn't make much sense in your example, isn't DOB vital to know if someone can drive a car?

But in an other example where date with default value is useful, I don't see the added value of using C#4 optional param with default value over using nullable type. Maybe nullable parameter even shows more intent that it can be null. Currently I do it like this in MR controller actions:

bool CanDriveACar(DateTime? born)

{

   born = born ?? DateTime.Now.Substract(TimeSpan.FromYears(18));

// proceed...

}

Yours does look a bit better from syntax perspective, but with more than 2 parameters you have to multiline them. And your idea could also have better support for intellisense I think.

But wasn't optional parameters mainly useful for reducing overloads and/or COM interop?

What would really be cool is a language where all arguments by default can not be null, checked at compile time. Get rid of all those NullReferenceExceptions and ArgumentNullExceptions. And then for all parameters, value or reference type, you can specify that it is optional using ?, just like you can do value types now in C#. I Don't think this will ever get in C# though... Maybe the ! syntax from spec# in C#5.

Krzysztof Koźmic wrote re: Thoughts on C# 4.0’ optional parameters
on 09-09-2009 3:29 AM

Alvin,

yes, maybe DOB is not the best example from domain perspective.

However, it is good enough for discussion of the syntax and language feature.

- allowing null for the sole purpose of having default value is confusing and misleading.

- the MR way you used as example is a workaround for that limitation.

- having that in the signature is better from readability perspective, code tidiness, and is clearly stating your intent what the real default is.

- yes, you'd often have to multiline that, I have no issue with that thought.

- yes the feature is mostly geared at COM interop. My point is, that in current shape it's crippled, while it could be easily (?)  extended to be actually useful for the general scenario.

- I read an interview once with Anders, when he said that the thing he regrets the most about C# design is that reference types are only nullable and value types non-nullable, and he wishes they had decoupled it. I don't think this will be part of C# 5.0 because it's baked into the very core of the framework and changing this would be a major breaking change.

Copious-Systems wrote Confused about Constructors in Java?
on 12-01-2010 2:51 PM

Someone referenced this post to answer question "Confused about Constructors in Java?"...

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)