I’ve known a bit about C# 4.0 for a while now and have had time to think about it. I’ve just re-read the New features in C# 4.0 paper published by Microsoft and would like to offer the following critique of the language’s new features:
Dynamic Lookup
This feature just makes me cringe, just like anonymous methods made me cringe when they were introduced in C# 2.0. To this day, I hardly use them, as they always feel like a kludge to me (lambda expressions fixed that).
The dynamic
keyword is as open to abuse as anything could be. It takes the principles of static typing and throws the baby out with the bathwater.
What is wrong with it
When looked at initially, the dynamic
keyword is great, because it simplifies and speeds up what is usually done with Reflection and Primary Interop Assemblies, both in the aspect of development times and the aspect of run time. Unfortunately, too much of a good thing is bad for you. Imagine the following:
public dynamic GetCustomer()
{
// mystery...
}
What do we have here then? I don’t know and neither does IntelliSense? I guess we’ll have to go with trial and error.
I admit this is quite the dramatization, but you get my point: it’s ripe for abusing an otherwise perfectly fine static syntax.
Moreover, the dynamic
keyword’s syntax does what no other feature of C# has ever done – it breaks existing syntax. Should I define in C# 3.0 a type named dynamic
, the following piece of code will take a whole different meaning in C# 4.0:
public dynamic GetCustomer()
{
dynamic customer = GetCustomerCOMObject();
return customer;
}
How it can be fixed
Using the dynamic
keyword is actually a built-in form of Duck Typing. The idea is good and should be introduced into the language, but I’d like to suggest a different way of doing it:
public ICustomer GetCustomer()
{
dynamic ICustomer customer = GetCustomerCOMObject();
return customer;
}
Here, what I get back is a dynamic dispatch object that must adhere to a specific interface. This means that the object graph is checked for conformity against ICustomer
the moment it is cast in the dynamic scope (i.e. returned from GetCustomerCOMObject
) and is from this moment on a typed object with dynamic dispatch under the hood. From this moment on, we couldn’t care less about whether this object uses dynamic dispatch or not, since we now treat it as a POCO.
This, along with removing of the ability to send dynamic dispatch objects through the call-stack (as parameters and return types), bringing them to the level of anonymous types, will help stop the deterioration of C# into a dynamic language.
Named and Optional Arguments
This is just silly. Really, this looks like some people cried “we don’t like overloads” hard enough and got some VB into the C# the rest of us liked the way it was. If you want to initialize your method with some of the parameters, use a builder pattern with an object initializer instead.
Here, I’ll take the sample at the bottom of page 6 and fix it, C# 3.0 style:
public void M(int x, MBuilder builder);
public void M(int x)
{
this.M(x, new MBuilder());
}
public class MBuilder
{
public MBuilder() { this.Y = 5; this.Z = 7; }
public int Y { get; set; }
public int Z { get; set; }
}
M(1, new MBuilder { Y = 2, Z = 3 }); // ordinary call of M
M(1, new MBuilder { Y = 2 }); // omitting z – equivalent to M(1, 2, 7)
M(1); // omitting both y and z – equivalent to M(1, 5, 7)
Yes, I do realize it’s mainly for COM interop, but most people will just get either confused by all the syntax, abuse it or simply forget it ever existed.
What is wrong with it
It exists.
How it can be fixed
Remove it from C#. There – fixed.
If you want optional parameters in your COM interop calls, just implement the correct overloads in the interface you create for use with the dynamic
keyword (see my suggestion for dynamic lookups) and the binding will be done at run time by the parameter names.
Variance, Covariance and Contravariance
These three features are long overdue and finally make an appearance in the language. It’s a great feature and I would love to integrate it into my code as soon as I possibly can.
I would love to know if there are plans to not only include reference conversions, but also the implicit and explicit conversion operators as qualifiers for VC&C.
What is wrong with it
Although Variance is implicit, the others are explicit. Using the Type<in T>
/ Type<out T>
notation is good for being explicit (for instance when you expect your interface to be expanded in the future), but it doesn’t have to be and can become a bit annoying over time.
How it can be fixed
The compiler can very easily infer the fact that your interface is either input-only or output-only and mark it as such for you. Language-wise, the explicit version should be kept available, for when you want to prevent someone (or yourself) from mistakenly adding a new method that breaks the your input / output only design.
Summary
It looks to me like the team behind C# is going in the wrong direction (DLR) instead of the right direction (Spec#), slowly turning C# into a dynamic language. It looks like all of this is done for the sake of easy interop with dynamic languages and COM objects. It looks as though the designers have succumbed to peer pressure. There are so many features missing from C# and the above are nowhere near the top of my list.
I can only hope someone is listening.