Named and Optional Arguments in C# 4.0

Many interesting news is coming from PDC this week.  Part of the announcements was around Visual Studio 2010 and the .NET Framework 4.0 CTP.  Microsoft has made available, a Virtual PC Image preloaded with Visual Studio.

You can download the preview information here:

 

One of the interesting features of C# 4.0 is for both named and optional arguments.  They are often very useful together, but are quite actually two different things.  Optional arguments gives us the ability to omit arguments to method invocations, whereas named arguments allows us to specify the arguments by name instead of by position.  Code using the named parameters are often more readable than code relying on argument position.  These features were long overdue, especially in regards to COM interop.  Both F#, and now C# have this feature which gives us greater flexibility is designing APIs.

 

Named and Optional Arguments in F#

As I’ve stated before, F# has had these features for both named and option parameters.  Let’s look at the implementation details of each.  Named arguments are simply when creating an object, specify the name before the assignment (=) operator such as the example below. 

let t = new TextBoxInfo(text = "Hello"
                        color = Color.Black) 

 

An optional parameter can be specified during the declaration by prefixing the argument name with a question mark (?).  This becomes translated to an Option<’a> type which allows for either some value or no value at all.  Should the value not be specified, you can set the default argument value through the let syntax.  Let’s walk through an example of a simple class called TextBoxInfo.

#light

open System.Drawing

type TextBoxInfo(?text:string, ?color:Color, ?font:Font)
  // Initialize
  let text = defaultArg text "" 
  let color = match color with 
    | None -> Color.Red 
    | Some c -> c  
  let font = match font with 
    | None -> new Font(FontFamily.GenericSerif, 10.0f) 
    | Some f ->
     
  // Properties
  member x.Text = text 
  member x.Color = color 
  member x.Font = font

 

Now that we’ve looked at the F# implementation, let’s look at how the C# team handled this issue.

 

The Implementation in C#

First, let’s look at the named parameters.  Much like F#, this process is rather straight forward.  Instead of using the assignment operator (=), the colon is used to denote the name and value pair.  An example of this using the above code would look like this:

var t1 = new TextBoxInfo(text : "Hello", size: 10.0f);
var t2 = new TextBoxInfo(size : 12.0f,  
    width : 50.0f);
 

These named parameters can be used not only on these constructors, but also methods, and properties with indexers.  Moving onto optional arguments, a parameter is simply declared optional by giving a default value to it through the use of the assignment operator.  Let’s take the above example written in F# and express is C# 4.0.

public class TextBoxInfo
{
    public TextBoxInto(
        string text = ""
        float size = 10.0f,
        float width = 50.0f,
        Color color = Color.Red) 
        
    { … }
}
 

But, this doesn’t work at all.  Why you ask?  Because, we require compile-time constraints, which means that we cannot initialize the default color this way.

compile_time_constraint

Instead, if we change the above code to use the default constructor of color, such as this, the error goes away.

public class TextBoxInfo
{
    public TextBoxInfo(
        string text = "",
        float size = 10.0f,
        float width = 50.0f,
        Color color = new Color())
    { … }
 

How useful is this then?  Not as useful as I’d hoped.  Once again, F# does get this right which allows us to initialize to whatever we so please, but it’s not done in the method signature, only the fact that it is an optional parameter.

Ok, so you’re probably asking about overload resolution.  Using this technique will affect the resolution of your given methods.  There are some rules that apply for resolution which are taken from the New Features in C# 4.0 document:

  • A method signature if applicable if all its parameters are either optional or have exactly one corresponding argument (by name or position) in the call which is convertible to the parameter type.
  • Betterness rules on conversions are only applied for arguments that are explicitly given – ommitted optional arguments are ignored for betterness purposes.
  • If two signatures are equally good, one that does not omit optional arguments is preferred.

We can take these rules to examine the following code:

MyMethod(string s1, string s2 = "Hello")
MyMethod(object o)
MyMethod(string s)
MyMethod("Hi!")
 

Given the above rules, the method that would be called would be the MyMethod(string s) as we take the signature that does not omit the optional arguments.  Now that we have the rules in place, we can be careful of how we structure our code.

 

Wrapping It Up

This is one of the first looks into the future of C#.  Much of the features of C# 4.0 are not around functional programming techniques as they were with 3.0, but still have some improvements.  The dynamic keyword is interesting, if not just for the COM interop story.  The ability to call into IronPython definitely makes the polyglot in me very happy.

As the language evolves, I believe we’ll find more emphasis on the surrounding frameworks for such things as concurrency and less on the language keywords themselves.  We’ve found that over time, if the language starts adding keywords, and somehow, for some strange reason, we’re wrong about the implementation, if prematurely ages the language and possibly sends it into irrelevancy.  I still have a wish list, a mile long for C#, but it’ll be a more interesting discussion of what part of that would more of a framework construct instead of a language one.

I encourage you to download the VPC of the Visual Studio 2010 and .NET Framework 4.0 CTP, try out the features, and give feedback!

This entry was posted in C#, F#. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://cherupally.blogspot.com/ Kiran Cherupally

    Hi all,

    I have added a post on this topic. Please read and post your comments/questions.

    http://cherupally.blogspot.com/2009/11/c-40-new-features-named-and-optional.html

    Thanks,
    Kiran

  • http://skurocks.wordpress.com/2009/05/06/optional-parameter-named-arguments-default-values-c-40/ Senthil
  • http://skurocks.wordpress.com/2009/05/06/optional-parameter-named-arguments-default-values-c-40/ Senthil
  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @Dmitri

    I agree, the usefulness drops somewhat when you realize that only simple types can be expressed this way. I’m not sure whether there is enough priority to fix any of this at all. I wish there were.

    Matt

  • http://nesteruk.org Dmitri Nesteruk

    I don’t like the way Color cannot be initialized – the usefulness of default parameters drops somewhat. Do you reckon this might be fixed before VS 2010 is out the door?

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @Andrew

    No, it’s a built in type to F#, under Microsoft.FSharp.Core.Option. I’ve created one as well in my Functional C# library on MSDN Code Gallery. : http://code.msdn.microsoft.com/FunctionalCSharp

    Matt

  • Andrew Shapira

    Which Option type are you referring to here – is that essentially what is presented here http://www.codeproject.com/KB/architecture/option1.aspx ?

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @Matt

    No, there is no typo. In order to use named parameters, you use a colon to separate the name value pairs. In order to use default arguments, you use an = assignment operator.

    Matt

  • http://sticklebackplastic.com Matt Ellis

    Matt, you mentioned that the syntax was to separate the parameter and it’s default value with a colon, yet all your examples are using the equals sign? Is that just a typo?

    Cheers
    Matt

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @Grant

    And you have default arguments in C++ as well, such as this:
    int print( double dvalue, int prec=2 );

    It’s interesting to say the least that C# was the last to get this feature. As I’ve said before, the real compelling argument for this feature is for the interop story with C++, VB.NET, dynamic languages, and especially COM interop.

    With any given technology or technique, you’ll find people screaming from the hilltop about possible abuse, but I see them playing out much as they did in the C++ world. Nothing to get super excited about in terms of that.

    Matt

  • http://grantpalin.com Grant Palin

    Heh, C# is catching up with VB…I think optional arguments were in VB6! :P

    Admittedly, the feature is not a silver bullet, but it can be useful from time to time. Time and place for everything. Having used optional arguments in VB.NET, I know that the way they affect overloading can make things tricky.