Friday, November 14, 2008

New features in C#4.0 (3)

Optional and Named Parameters
Optional parameter is a long-standing request from the community that made it to C# 4.0. By itself, the feature is definitely useful but in conjunction with the mission to make COM Interop easier, there's even more value to it.
Optional Parameters
(1) The syntax
C# 4.0 can both declare and consume optional parameters. Here's a sample of a very simple method that declares a parameter as optional:
public static class OptionalDemoLib
{
public static void SayHello(string s = "Hello World!")
{
Console.WriteLine(s);
}
}
This means you can either call Do with one argument or without an argument, in which case the default value is used:
public static class OptionalDemo
{
public static void Main()
{
OptionalDemoLib.SayHello(); OptionalDemoLib.SayHello("Hello Bart!");
}
}
Notice all optional parameters need to come at the end of the argument list.
(2) The implementation
How does it work? Let's start by taking a look at the definition side. Here's the IL corresponding to the declaration of SayHello above:

Two things are relevant here. First of all, the parameter is decorated with the [opt]. Second, the method body contains a .param directive. It turns out both of those primitives have been supported in the CLI since the very beginning. Let's dive a little deeper using the CLI specification, partition II:

15.4 Defining methods
opt specifies that this parameter is intended to be optional from an end-user point of view. The value to be supplied is stored using the .param syntax ($15.4.1.4).

15.4.1 Method body
.param `[` Int32 `]` [ `=` FieldInit ] Store a constant FieldInit value for parameter Int32.

15.4.1.4 The .param directive
This directive stores in the metadata a constant value associated with method parameter number Int32, see $22.9. (...) Unlike CIL instructions, .param uses index 0 to specify the return value of the method, index 1 to specify the first parameter of the method, ...

22.9 Constant : 0x0B
The Constant table is used to store compile-time, constant values for fields, parameters, and properties. The Constant table has the following columns: - Type ... - Parent ... - Value (an index into the Blob heap) Note that Constant information odes not directly influence runtime behavior, although it is visible via Reflection. Compilers inspect this information, at compile time, when importing metadata, but the value of the constant itself, if used, becomes embedded into the CIL stream the compiler emits. There are no CIL instructions to access the Constant table at runtime.
Default parameter value must be a compile-time constant.

Named Parameters
(1) The syntax

Assume the following simple subtraction method is defined:
static int Substract(int a, int b)
{
return a - b;
}
The typical way to call this method is obviously by specifying the parameters in order, like Subtract(5, 3). However, with named parameters it's possible to write the following:
public static void Main()
{
Console.WriteLine(Substract(b: 3, a: 5));
}
Ultimately this translates into a call to Subtract(5, 3). Typically named parameters are used where optional parameters appear in the target method, but you're not interested in lots of those:
static void Bar(int a = 1, string b = null,bool c = false)
{
// ...
}
static void Bar(int a = 1, string b = null, bool c = false){ // ...}
Now assume you're only interested in the last parameter, without the named parameter feature you'd have to write Bar(1, null, ...) but now you can go ahead and write:
Bar(c: true);
Bar(c: true);
You might wonder why the syntax uses a colon (:) instead of an assignment equals character (=). The answer is straightforward: assignments have a value and can be used everywhere a value is expected:
bool c = false;
Bar(c: true);
bool c = false;Bar(c = true);
This will assign true to the local variable c and feed that value in as the first argument of Bar. So colon is the way to go.
(2) The implementation
It should be clear that the implementation only affects the call site, not the caller. Here's how the Main method from above looks like:
First of all, notice the names of parameters don't appear in the call site in any way (they never have, that's not the way IL works). Ultimately we simply call Subtract with the parameters supplied in the right order. But how we get there is important to take a closer look at:
IL_0001: ldc.i4.3
IL_0002: stloc.0
IL_0003: ldc.i4.5
IL_0004: stloc.1
IL_0005: ldloc.1
IL_0006: ldloc.0 IL_0001: ldc.i4.3
IL_0002: stloc.0
IL_0003: ldc.i4.5
IL_0004: stloc.1
IL_0005: ldloc.1
IL_0006: ldloc.

The thing to notice here are the mirrored stloc (store to local variable) versus ldloc (load from local variable) instructions. And ldc.i4.num is used to push num on the stack as Int32. On lines IL_0002 and IL_0004 values are stored to variables 0 and 1, while on lines IL_0005 and IL_0006 they're read out in reverse order. What's happening here is that during the run-time processing of a function member invocation, the expressions or variable references of an argument list are evaluated in order, from left to right. Obviously, the complier has to do something to keep the order correct.

4 comments:

Anonymous said...

Your blog keeps getting better and better! Your older articles are not as good as newer ones you have a lot more creativity and originality now keep it up!

Anonymous said...

Nice brief and this fill someone in on helped me alot in my college assignement. Thank you as your information.

Anonymous said...

Good afternoon

We do not agree with this year Brit awards decision.

Please visit our little web survey

http://micropoll.com/t/KDqOnZBCWt

Lady Gaga can not be better than Nina Hagen

Poll supported by BRIT awards 2010 sponsor femmestyle
[url=http://www.femmestyle.ch/earcorrection.html]ohrenkorrektur[/url]

Pet Shop Boys surprise lucky BRITs fan with a MasterCard Priceless Gig in their living room

Anonymous said...

Good dispatch and this fill someone in on helped me alot in my college assignement. Gratefulness you for your information.