Geeks With Blogs
Running with Code Like scissors, only more dangerous

When I was first getting into C# (about .NET 1.0 Beta 2), I saw that it didn't support optional parameters.  The explanation was simple enough: method overloads supported an alternative method of default or optional parameters.  I thought that it was probably a useful choice.  But, check this out:

   1:  public static class MessageBox
   2:  {
   3:      static void Show(string message)
   4:      {
   5:          Show(message, null, MessageBoxButtons.OK, MessageBoxIcon.Information);
   6:      }
   7:   
   8:      static void Show(string message, string title)
   9:      {
  10:          Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information);
  11:      }
  12:   
  13:      static void Show(string message, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
  14:      {
  15:          // actually perform the showing
  16:      }
  17:   
  18:      // and more overloads
  19:  }

This is pretty lame, isn't it?  Why can't I just do everything with a single method?

   1:  public static class MessageBox
   2:  {
   3:      static void Show(string message, string title = "", MessageBoxButtons button = MessageBoxButtons.OK, 
   4:          MessageBoxIcon icon = MessageBoxIcon.Information);
   5:  }

So, the question is, how precisely could this work?  Well, let's take a look at how this works in Visual Basic.

   1:  Public Class MessageBox
   2:      Public Shared Sub Show(ByVal message As String, Optional ByVal title As String = "", _
   3:                             Optional ByVal buttons As MessageBoxButtons = MessageBoxButtons.OK, _
   4:                             Optional ByVal icon As MessageBoxIcon = MessageBoxIcon.Information)
   5:      End Sub
   6:  End Class

Visual Basic turns this into a method and annotates the parameter list with attributes.  In C# we could express it like this:

   1:  public static class MessageBox
   2:  {
   3:      static void Show(string message, 
   4:          [Optional]
   5:          [DefaultParameterValue("")]
   6:          string title, 
   7:          [Optional]
   8:          [DefaultParameterValue(MessageBoxButtons.OK)]
   9:          MessageBoxButtons buttons, 
  10:          [Optional]
  11:          [DefaultParameterValue(MessageBoxIcon.Information)]
  12:          MessageBoxIcon icon)
  13:      {
  14:   
  15:      }
  16:  }

In languages that support optional parameters, the compiler provides parameters, so that a call that leaves off optional parameters looks (in IL) like a call that included the parameters.

I suggest that we use a compiler trick - dump the attributes and actually implement the overloads.  This has the awesome benefit of being entirely compiler-dependent and entirely backwards-compatible even to .NET 2.0.  We can even include one overload with the attributes included, so that development tools and compilers that use the attributes can tell the user about the optional parameter information, and the existing compilers can compile against a library using the new methods.

Consider this overload based on the above demonstrated Show method.

   1:  public static class MessageBox
   2:  {
   3:      static void Show(string message, MessageBoxIcon icon)
   4:      {
   5:          Show(message, "", MessageBoxButtons.OK, icon);
   6:      }
   7:  }

This function has the advantage of being inline-able, even if it means a slightly (and I mean ever-so-slightly) hit to file size.  I'm not saying it'd be good or effective to have 10 optional parameters - just that it wouldn't be bad to have a few.

Finally, my suggestion for the syntax of how this all should work out - use the default keyword for each item when you want to specify options:

   1:  void Go()
   2:  {
   3:      MessageBox.Show("This is a test.", default, MessageBoxButtons.OK);
   4:  }

CLI implementation provides an attribute on the actual implementing method so that we can figure out which is the actual default value - the compiler then has the option of whether to call substituting in the actual value (as it's implemented in VB now) or call the correct overload (which is what the current C# compiler would do).

Posted on Tuesday, January 15, 2008 8:49 PM | Back to top


Comments on this post: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
Thanks, really interesting read and i feel the exact same way :D
Left by Paul on Jan 16, 2008 11:38 PM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
oh yeah... missing that from the good old Delphi days
Left by Eber Irigoyen on Jan 17, 2008 10:26 AM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
Overloads only work if the optional parameters are of different types. If I have a method with 3 optional boolean parameters there is no way to provide all the possible combinations with overloading.
eg:
public function GetRoute(byval RouteDef as thing, optional AvoidMotorways as boolean = false, optional Shortest as boolean = false, optional Fastest as boolean = false)

You can't provide all the possible combinations of optional parameters using overloading.
Left by sab on Feb 21, 2008 4:55 AM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
Yes, the lack of default params can be annoying, especially as the overloads we end up defining, could easily be defined automatically for us, a-la C++. I suppose MS's thought process was to remove the ambiguity problems associated with C++.

With regard to the optional parameters, that can already be done in c#...

class poo
{
public string Name;
public string Phrase;
}

new poo(Name="MrHanky",Phrase="Howdy Ho");


FAR more important to C# 4.0 would be:

1: An "INumber" interface for all numeric integral types
2: user operators can be added to interfaces

This would allow (astonishingly missing) generics vectors. There is curently no way the following can be implemented without abusurd level of work (essentaily rewriting int, float & double!):

class Point3D<T> where T: INumber
{
T SomeCalculation()
{
return x+y+z;
}
T x,y,z;
}

3: array initialisation in parameters. Why can we do this:

class foo
{
string [] bar = {"foo","bar"};
}

but not this?

void foo( string[] bar) {}

void fooBar()
{
foo({"foo","bar"});
}

( yes you can use the "params" keyword, but that provides very different sematics to the function usage
Left by Adam on Sep 07, 2008 9:37 AM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
@Adam: the INumber interface does not need a change in the language, but a change in the "System" library.


Also, I don't think that the above solution for default types using "Default" and "DefaultParameterValue("")" is not very clean. "DefaultValue" can do the job alone:

void Foo( [DefaultValue(DefaultReturnValue)] Type ParameterName) {
...
}

Also

void Foo( [DefaultValue()] Type ParameterName) {
...
}

might give "null" as Default. The "default"-keyword can be keept.
Left by MovGP0 on Oct 05, 2008 6:41 AM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
@MovGP0: You are correct, the INumber interface doesn't require a change in the language but in the system library. I'd love to see something like that but I'm not holding my breath.

Also please note that the DefaultParameterValue() approach isn't my suggestion - it's the way it is currently implemented within the CLR (as demonstrated as part of C++ or Visual Basic) - see the existing documentation at http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.defaultparametervalueattribute(VS.80).aspx
Left by Rob on Oct 06, 2008 1:51 AM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
> public function GetRoute(byval RouteDef as thing, optional AvoidMotorways as boolean = false, optional Shortest as boolean = false, optional Fastest as boolean = false)


Er.. you'd have a Flags Enum that specified parameters of the same type.

Note that your method signature is perhaps a bit dumb, because you cannot ask for both the fastest and the shortest route.
Left by a on Oct 14, 2008 8:20 AM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
Um, no.

1.) You wouldn't want to have simply a Flags enumeration to determine which path of logic to take, as that would be "logical cohesion", which is one of the worst types of cohesion a routine can have. For more information, see http://en.wikipedia.org/wiki/Cohesion_(computer_science)

2.) You can indeed ask for both the fastest and shortest route, because they're not always mutually-exclusive. For instance, you might have a frontage road adjacent to a freeway and the route taking the frontage road is 0.5mi shorter; however, because the freeway goes 20mph faster, the freeway route is faster. If both parameters are true, there could potentially be a different route, or the method author might choose which has more weight. An algorithm may determine it. The bottom line is that you're wrong for calling out that particular comment.
Left by Rob on Oct 14, 2008 8:38 AM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
I think that the real reason C# doesn't provide a mechanism for default parameter values is that it would conflict with the delegates mechanism. The same goes for all the .NET languages. The only exception is native functions in C++/CLI.
Left by Ron Inbar on Nov 04, 2008 5:57 AM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
Actually, C# will begin supporting optional parameters in C# 4.0.

http://channel9.msdn.com/pdc2008/TL16/

It was supported in Visual Basic since 1.0! :)
Left by Rob on Nov 04, 2008 7:20 AM

# re: My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters
Requesting Gravatar...
I'd prefer to see it similar to constructor inheritance, honestly - without providing a body.

void foo(string s) : this(s, 1);
void foo(string s, int i) {
}

I don't mind writing out all the overloads to prevent ambiguity! I just don't want to end up with giant call stacks because I don't want to type null or enum.default for rarely-used parameters.

Left by Brian on Jan 27, 2009 1:12 AM

Your comment:
 (will show your gravatar)


Copyright © Robert Paveza | Powered by: GeeksWithBlogs.net