Friday, 22 June 2007

C# 3.0: Implicitly typed local variables and implicitly typed arrays

We are working on full C# 3.0 support for the Mono gmcs compiler and today I am pleased to announce full support of implicitly typed local variables and implicitly typed arrays.

Implicitly typed local variables

Those who have never heard about implicitly typed local variables maybe noticed new C# 3.0 keyword called `var'. However, the var is not a real keyword; it is what I would call transparent keyword. It behaves like keyword but only if there is no collision with a type of the same name. The rationale behind this is obvious, to make migration to new version as smooth as possible. Therefore, if your existing code uses type called var, don't worry, it will still compile in the same way as it did with the previous version of C# compilers.

As the name says one can use var to implicitly type local variable as shows the following example.

using System;
class ImplicitlyTypedLocalVariables
{
public static void Main ()
{
var max = 10;
for (var i = 0; i < max; ++i)
{
Console.WriteLine (i);
}

var values = new string[] { "a", "b", "c" };
foreach (var s in values)
{
Console.WriteLine (s);
}
}
}

Everywhere var keyword is used, the compiler tries to infer the variable type based on a type of variable initializer. This limits implicitly typed local variables to be used only in a local variable declaration, for each, for, or using statements.
Also as the name says, implicitly typed local variable, you cannot use var for field declaration or constant variables, therefore following declarations will both produce a compiler error.

class Errors
{
var i = 0;
public static void Main ()
{
const var c = 2;
}
}

I am not sure why there are such limitations but I am probably missing something.

Implicitly typed arrays

Implicitly typed arrays are another new C# 3.0 feature probably not as well knows as the var keyword but it can be also useful.

class ImplicitlyTypedArrays
{
public static void Main ()
{
var a1 = new[] {"a", null, "b" };
var a2 = new[] { -1, 0, 2.0 };
var a3 = new[,] { { "a" }, { "b" } };
}
}

Interesting, C#, statically typed language and I cannot see any type whatsoever. How does it work then? It is not that hard to guess, as many other new C# 3.0 features also this one uses type inference. So, if it is possible the compiler tries to infer an array type based on common type (implicit conversion has to exist) of all elements in the array initializer otherwise a compiler error is issued and you have to specify type explicitly. The current draft of C# specification does not mention anything about implicitly typed multi-dimensional arrays. However, the latest Microsoft compiler supports implicitly typed multi-dimensional arrays with the syntax similar to an explicitly typed array. Although they are supported, hard to say whether it is a bug or a feature with required comma syntax.

Thursday, 15 February 2007

C# 3.0 Extension Methods

Mono compiler gets the full support of extension methods, the first C# 3.0 feature. A patch which adds extension methods support to gmcs just landed on SVN. Let’s look at some interesting details.

Extension methods are static methods that can be invoked using instance method syntax. In effect, extension methods make it possible to extend existing types and constructed types with additional methods. -- C# 3.0 Specification

Sounds good, so how can I make my method extension method?

A method became the extension method when the first method parameter contains `this’ modifier. Extension methods can be declared in non-generic top-level static classes which mean that extension methods can be declared as static only. There are further limitations but they only covering corner cases. For those interested, I recommend browsing Mono compiler test suite to get some ideas.
static class MyExtension
{
public static string Prefix (this string s, string prefix)
{
return prefix + s;
}
}

class M
{
public static void Main ()
{
string s = "abc".Prefix ("1");
}
}

Note: If you want to use extension methods you need to pass `langversion:linq’ option to compiler to unlock C# 3.0 specific features; although extension methods are included in gmcs compiler.

When you try to compile the sample, it will compile successfully and an instance method call will be converted to a static method call by compiler. How is it possible? The method `Prefix’ is the extension method of `string’ class and no other method with same parameters exists and therefore the method is selected as the best overload candidate.

Wishing to use extension methods in more advanced scenario, things become little bit more complicated and you have to use `using ’ to import your extension methods from different namespace or an assembly.

Confusing, isn’t it? Well, not that much. Extension methods are included in method resolving process if standard (non-extension) process failed to find a match. The compiler will look for extension methods in the current namespace context and if no suitable method was found, the process will continue inspecting all referenced namespaces in the current namespace. In the case of method was not found, the compiler continues in parent namespace until either method is found or parent namespace does not exist.

My overall feeling about the feature is mixed as extension methods clearly reduce code readability. Fortunately, I was pleased to read the recommendation "to use extension methods sparingly and only if it is not possible to use instance methods" directly inside C# Standard.