My View of C# 4.0

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

Microsoft PDC 2008 by Manohar Dasari, CC-BYThis 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

Untitled by Long Zheng, CC-BY-NC-SAThis 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

Anders Heilberg at book signing by DBegley, CC-BYAlthough 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.

22 Comments

  • impressive... just because you don't know how you would use a new feature, doesnt mean it should be removed for everyone else who embraces it.

    just like with anonymous methods that you apparently haven't figured out how to use, many of us have been using them quite happily and can't imagine being without.

    yes, named arguments could be replaced with something else... but then, we dont really need classes or objects... people used to write in functional languages and some still do... would you you like to go back?

    MS is unusually forward looking with the .net platform sometimes and pays attention to the programming trends... a lot of these features come from ruby which is gaining a very strong momentum not just because of ror, but because it's actually a superb language.

    btw... peer pressume is otherwise known as community, and MS can only be praised for listening and following it.

    how about you list your missing features instead of just dissing? you know... everyone's a critic, how about you be constructive?

  • Your comments about (semi-) Duck Typing are, sorry, wrong. You assume that a given dynamic object is, well, static, at least from the POV of the methods it has. But the Framework supports (since CLR 2.0), the System.Reflection.Emit.DynamicMethod method, that lets you create new methods at runtime. So a class that's interrogated for its methods at first reference doesn't work in this case.

    And I think IronPython and/or IronRuby (and the DLR) support this.

  • As an ActionScript 3 developer .. I'd say your overreacting.

    ActionScript 3 also has the dynamic feature ....

    public dynamic class Foo { // dynamic class
    public var bar:* // dynamic var
    }

    And I rarely see them being used. The advantage of using strict typing is just too strong. If I were to ever use dynamic, it would be in a private closure; away from my integration points.

  • this is why 8 year old's should not be allowed to write programming blogs

  • <>

    Sorry ? If anything, Functional languages (like ML, Haskell, Clean, OCaml, etc ) seem to be more advanced, not retarded, than what you have there

  • Andrew, These are my opinions and you are welcome to express and discuss yours here as well. Derogatory comments aren't discussion.

  • Paul, I'm very straightforward with expressing my views. I really do think that there is a problem with these features. If you want to address my points, rather than the way I express them, you're welcome to comment to the point.

  • I'm a bit undecided on the dynamic variables - I'll let the COM experts worry about those, but I don't see how optional parameters can hurt the language.. Sure, you can use the builder pattern (thanks for teaching me something new, by the way!) but why not support something natively?

  • Craig, I like taking action to prevent future mistakes from happening and one of these things was to offer critique about the new features. My intention was to keep the possible abuse of the language to a minimum, while maintaining these new, very nice features.

    Vanja, I'm just concerned about adding more and more unintuitive syntax to the language. Keywords are usually self-explanatory and syntax is not. This is a duplicate feature of overloading and is only there to appease the COM crowd.

  • I wholeheartedly agree with you! I rather see C# go the verifiable (Spec#) direction instead of the dynamic direction.

  • When I had looked at features provided by Ruby, I was concerned that if this features are used by people who have just started coding, then they might turn it into a mess. Eventually, I figured it out, that new programmers won't even look at using those features as they would not even understand it.

    To understand the use of these advanced features, you need to have experience. You need to come across a situation, where you have to maintain a duplicate code in methods just because they use objects of different types, but use same properties. This is the time when you really feel need for Duck-Typing or Dynamic keyword.

    Personally, I like to keep code as small as possible. Introducing overloading over methods only to support different count of parameters will simply increase the lines of code. This is where use of methods supporting optional parameters come to rescue.

  • Interesting... it seems that no one in the comments agrees that the new features should not be introduced into the language. I wonder why. Oh may be because they are good. Also it is strange how the C# team spent years designing this features but you managed to label them bad or dangerous in just a day. It is ok to say that a feature is bad if you had used it and you've seen it abused but how are we to believe anything you say when you have not written any code using these features and obviously the C# team has experience in designing programming languages and have tested it with at least some code?

    "most people will just get either confused by all the syntax"

    People who cannot learn the syntax of a language should not be allowed to code in it and people who use features they do not understand should be shot, period.

    oh and BTW I use anonymous methods (I would use lambdas of course but I am stuck with C# 2.0 for some time) more often than I declare interfaces. Shall I requests that interfaces are removed from the language?

  • Stilgar, I'll take on your points one by one:

    "it seems that no one in the comments agrees that the new features should not be introduced into the language"
    You should re-read the comments then ;)

    "It is ok to say that a feature is bad if you had used it and you've seen it abused"
    And what about using my past experience to deduce it in advance? Is that not a valid means? Am I supposed to sit back and wait until it RTM's and only then say my piece only to have no one listen to it because it's already out?

    "obviously the C# team has experience in designing programming languages"
    Does it mean that everyone who has any experience in programming languages think in unison?

    "People [...] should not be allowed to code in it and [...] should be shot, period."
    I decided to go with the more subtle approach of prevention.

    "I use anonymous methods (I would use lambdas of course but I am stuck with C# 2.0 for some time) more often than I declare interfaces. Shall I requests that interfaces are removed from the language?"
    You would have been welcome to ask for that when C# 1.0 beta spec was released, although I imagine that without a concrete reason, no one would listen to you. After all, you didn't give a reason why it shouldn't be in the language. Oh well.
    Right now you can't just remove a feature people still use anyway.

  • Stilgar,

    My idea was that you could use an interface to strongly type the calls you can make on that object. If you add a new method, use a different interface to call it.
    I doubt external interfaces from dynamic languages have changing contracts, but it is a possibility.

    I was thinking about suggesting "dynamic var", which would be just like what the current "dynamic" offers, but is limited to the scope of a method, like var would be. Not entirely sold on the fact that it really is something that needs to be in the language so badly.

  • It has always been a key goal for the .NET platform to support multiple languages unified within a single type system. Extending the platform to support functional and dynamic paradigms merely broaden the platforms reach and will serve to make integration and interoperability easier. It also allows us to reuse our C# skill sets for when we only want to do rapid prototyping, something that previously would be better served by other languages. Also, Anders was very specific about how these new dynamic language features should not be seen as a move away from statically typed languages.

    Default parameters really should just have been part of C# 1.0. I can't tell you how tired I am of adding method and especially constructor overloads to make the code easy to consume while keeping it flexible.

    DBC and Spec# will be much easier to implement with the new compiler and language object model planned for C# 5.0, as you get hooks directly into the code generation instead of relying on post-weaving IL into an already generated assembly. We'll just have to wait a bit.

  • I wouldn't call "sending a struct as a constructor parameter" a "builder pattern"...
    Kinda like Optional Arguments...
    It means less code, less complexity and clearer more readable code...
    Yes, you can abuse it and send tens of optional parameters instead of a struct (like they do in other platforms. FYI SAP ESA services...) but you can say that about any feature (LINQ? :))

    Anyway, the real question seems to be around dynamics...
    As much as a dislike dynamic languages, as someone who had to suffer writing managed-to-COM integrations I think this feature is pure blessing.
    I remember having to deal with Office interfaces (Outlooks, "Send To" dialog, the messenger smart tag...) that that were simply un-callable, even when I resorted to all sort of reflection trickery...

    You have to remember that most of the IT world (and Microsoft customers) are still using legacy unmanaged code...
    The adoption of .NET isn't as wide as Microsoft wanted it to be and it has to take some steps to encourage migration.
    Supporting dynamic languages also means Microsoft is aiming to please them JavaScript, Ruby times... Face it, those guys rule the internet and Microsoft needs them on its side...

    Spec#? that's enterprisey territory where Microsoft already has a stronger offering...

    As for my battle with Office COM objects? I had to resort to VB where the thing just worked... but it was on VB... if anything should be killed, its VB....


  • Hi Omer,

    Your comment about the breaking nature of the dynamic syntax is incorrect. The compiler will only bind the typename "dynamic" to the new dynamic type if that typename does not already bind to an existing type in the scope in which you use it. In that sense, it is similar to "var," which did not break code that used that term already.

    We try to be pretty careful about things like this.

    chris

  • Hi Chris,

    Thanks for clarifying that. I was a bit worried about it breaking existing strong typing.

    I'd appreciate it if you could refer to the other points I make and my suggestions as well.

    Omer

  • I can't see why this would pose a problem. After all, IDynamicObject is a CLR interface too.

  • Hey Tobi,

    Your code is nice, but the reason behind my post was to try and mitigate the possibility of abuse (by someone who didn't know how to use dynamic correctly), while yours is for those who already know what dynamic is and want to work more statically with it.

  • It's a good idea if you want to decouple badly written dynamic code from the rest of your code to expose interfaces in the way you suggested.

    My biggest concern is that I will get a 3rd party assembly (or some other code that can't be changed) that exposes a dynamic value. I can stay out of the way of dynamic for as long as I like, up until that moment when someone forces me to use it in that fashion.

    Good point on the argument naming. IMHO, If I could create overloads by name, that would be the only reason for being able to break code that refers to names.

  • "Come on - method parameter names MUST be private to the method, it's the only way I can refactor and clarify!"

    Why? Renaming methods is a breaking change; how is renaming parameters fundamentally different? If you care at all about language interoperability, then changing parameter names is already a breaking change in the .NET world, unless you are just writing off anyone who uses VB.NET. Just because you've been doing it and getting away with it doesn't mean you are doing the right thing.

Comments have been disabled for this content.