Thursday, January 03, 2008

C# 3.0 var Keyword, Type Inference and Anonymous Types

The var Keyword

C# 3.0 introduces a new keyword var.  Most often, this keyword shows up when using Linq and lambda expressions.  The var keyword isn't limited to lambda expressions though.  The following code is completely valid as well.

var integer = 1;
var boolean = true;
var myString = "Hello World";

If you take a look at the output of this code in Reflector, you'll see that the C# compiler infers the type from the data bound to the variable:

int integer = 1;
bool boolean = true;
string myString = "Hello World";

This is the identical IL output you'd get from statically typing the variables.

From looking at this then, you can gather that the type inference is not late bound, and the type is inferred at compile time.  So, for instance, if you do the following, you'll get a compile error:

var integer = 1;
integer = true;

The compile error you'll get is "Cannot implicitly convert type 'bool' to 'int'".

Anonymous Types

Now, another new feature of the compiler that builds upon this early binding, is the concept of Anonymous Types.  This combines the concept of the var keyword and object initializers.  Here's a quick and simple structure that you can create on the fly:

var myAnonType = new {
    FirstName = "Jim",
    LastName = "Fiorato",
    Age = 32 };
 
Console.WriteLine("{0} {1} = {2}",
    myAnonType.FirstName,
    myAnonType.LastName,
    myAnonType.Age);

Now, what I would expect to see in Reflector, is a class that has been generated, and that class being populated where you see the anonymous type declared in the code above.  However, this isn't the case.  What I found is that the code in Reflector is identical to the code that you see above.  That would suggest that in the case of anonymous methods, the create of the type is done late in the game, at runtime.  That can't be the case though, because our runtime hasn't changed, just the compiler.

As it turns out, Reflector understands how anonymous types are generated, so we're going to need to open up the IL to view what is generated:

IL of Anonymous Types

This is a pretty interesting compiler feature.  The var keyword itself is unlikely to be used in the scenario I outline above, but I'll use it often while using Linq.  When using Linq, I'll want the compiler to infer the type of query object returned from the expression.

For anonymous types, the usages are a little more obscure.  But I think back to all the tiny little data structures I've created in the past as structs to store a data structure, usually within the scope of a method.  Anonymous types would be able to save me the struct declaration in this case.

Anonymous Types and Duck Typing

One thing that's interesting with Anonymous Types is the concept of Duck Typing.  Here's a link that describes Duck Typing in a little more detail.  But essentially, duck typing says that if the object has identical operations and attributes as another object, then those two types must be the same ("If it walks like a duck and quacks like a duck, then it must be a duck").

Could you Duck Type an anonymous type into a concrete type?  What kind of options would this provide for mocking within unit tests?  Could I mock an object as an anonymous type?

Some more to explore...

2 comments:

Will said...

So Variants have been introduced into C#? My first reactive is fear. Weak typing and variants were one of biggest weaknesses of VB 6 and earlier. There are many articles written about the problems this introduces and the potential bugs this can cause. I suspect that this is different and that this has been addressed, but it would be interesting to research how they addressed these concerns.

Jim Fiorato said...

Hey Will

They're a LOT different than the variant data type of VB. VB variants were late bound, and only assumed the type during runtime.

C# 3 var keyword only defers the type inference to compile time, early bound. So, it's much, much safer to use than the VB variant.

Now, for the type inference that is done at compile time for things like Lambda and LINQ expressions on sets of data, the type inference gets a bit more complicated, but it's still being done at compile time.

It's a somewhat dynamic typing system. and it's all done by the compiler.

The C# 3.0 compiled code operates in the 2.0 .NET Runtime. A late bound variant feature would require a runtime upgrade.