I am very happy to announce that the Mono C# compiler is now C# 4.0 feature complete.
Covariance and contravariance
The initial work was done by Scott Peterson and then I take taken over and continue developing and advancing the feature. The implementation was rather straightforward especially because C# 4.0 only supports covariance and contravariance on delegates and interfaces. The trickiest and most challenging part was to upgrade type inference to deal with variant type arguments and to provide a meaningful error reporting.
Optional parameters as of C# 4.0 are limited to the CLR 2.0 functionality which in plain speak essentially means that only constant expressions are supported. The feature adds what VB supported for quite some time but does not add anything new although the integration with existing features like nullable types has been done.
This is probably the trickiest new features of C# 4.0. It may look like simple add-on but by its nature it relates to the most complicated part of C# language. There were several areas where we had to be careful such us overload mechanism, side effects execution, virtual methods, and partial method integration. Most importantly to ensure left to right evaluation any non-constant expression is always copied before next argument is evaluated. This could have a small performance penalty but it was necessary to make our implementation robust.
I am not going to explain what dynamic binding is as many people did it before and it can be easily found on the Internet. Instead I am going to focus on how we have implemented it and where it fits to Mono stack.
Dynamic binding is fully integrated into the C# language and any statically bound expression can also be bound dynamically using the new “dynamic” type. This may sound easy but it has been a lot of work even if we had sources of Dynamic Language Runtime (DLR) available when started it and Mono C# compiler has been written in C# from the begging. To better illustrate the concept from compiler perspective here is the structure we ended up with.
Static compilation is on the left side, we can call it a phase I, where everything goes as usual until keyword “dynamic” is resolved in C# source file. At this point all what can be done is to pack the expression and its context into what is usually called payload and redirect the resolver to this payload which gets later emitted instead of evaluated expression. At this point I'd like to point out that even if C# compiler defers the actual resolution to runtime it still tries to do as many static checks as possible to reduce number of possible errors from dynamic binder.
Now we have successfully compiled our application and we can run it. Any dynamic binding code can only run on Mono trunk or .NET 4.0 as it requires a new dynamic binder infrastructure which had not been available in versions before. What you can see on the right side of the image is the magic box called DLR which is the dynamic infrastructure handling all dynamic operations on top of CLR and that's where we come back to life with our dynamic C# binder. We defer all dynamic handling to DLR and only register our payload with DLR call-site so we can be called when DLR decides there is a need for dynamic resolution. When such situations happens C# runtime binder loads the payload created in the phase I and calls back the Mono C# compiler resolver with the restored expression and the context mimicking the static compilation. This has huge benefits for Mono as we have a single code base for both static and dynamic binder. It also has a positive impact on dynamic binder as errors reported during runtime execution will be exactly same as with static binder.
It's also worth mentioning that DLR works strictly with objects only which means any value types dynamic operation will require numerous boxing and unboxing operations and that will slow it down the operation significantly and should be therefore considered before using with dynamic binder.
What about other C# 4.0 features?
There is not really that much left. We have decided not to implement true COM interoperability features for now as we see a minimal usage for them in Mono stack however we may reconsider it at a later stage.