I have moved!

I've moved my blog
CLICK HERE

Tuesday, 4 November 2008

Dynamic typing in C# 4 and Duck Generics

When the dynamic typing proposal for C# came out, my feedback was basically that you can already do it in the language today:

DynamicObject Wrapper

The justification for adding dynamic is that it gets rid of a lot of ugly reflection. But delegates and indexers mean that the language already has almost enough expressiveness to hide those details entirely.

Now the proposal is getting a lot firmer and there's a CTP available, more people are voicing their concerns. I remain pretty unconvinced of the value of it. One good point made by several people now is that it ought to be possible to use an interface to describe the set of operations that an object must support. The object wouldn't have to genuinely implement the interface - the IDE would just use the interface's members to offer up auto-completion in the usual way. The compiler would then simply generate dynamic calls, so the interface would be irrelevant at runtime.

I go further: I'd prefer it if this was mandatory. I like it when an assumption or fact about the program is defined in one place - a single definitive statement of that fact. This is much better than having multiple implicit suggestions spread all around the program.

That is unlikely to happen, because it would cause some unrealistically trivial examples grow a few lines longer - shock horror.

This all reminds me of something I've wanted in C# ever since generics were added, which is what I'm going to call "duck generics" - essentially, generics that work more like C++ templates. One saving grace of dynamic calls in C# 4 is that they suggest a new way to solve this problem.

Here's a typical generic class, C. Any type can be the type parameter T as long as it implements ISocket:

public interface ISocket
{
    byte[] Read(int maxBytes);
}

public class C<T> where T : ISocket
{
   ...

The problem is, what if I have a few 3rd party classes that each have exactly the right kind of Read method but don't implement the ISocket interface? Today, I would have to hand-write a forwarding class for each of them.

Previously I've wondered if it would be practical to make the compiler do exactly that for me. Whenever a concrete instantiation of C is created, the compiler would automatically generate a class that implemented ISocket and forward the Read call on to the "real" object.

I think it's a good idea. It doesn't require changes to how generics are declared, or how they are defined, except that typeof(T) on a type parameter would have to tunnel inside the forwarder to get the real type. It would be another example of pure 'syntactic sugar', automating away the need for tedious hand-written code, just like 'yield return' and the 'using' statement, and so on.

Anyway, now there's dynamic calling, another possibility exists, which is to add an alternative syntax:

public class C<T> where T dynamic ISocket

It tells the compiler to allow me to treat T as if it implemented ISocket, and to generate dynamic calls for anything I do to an instance of T. When I instantiate C<S> the compiler checks that S has all the operations needed to satisfy any dynamic call to a member of ISocket. So we still have perfect static type safety; the dynamic calls in my generic class are guaranteed to succeed.

There would be no need to generate forwarder classes, or to make instances of those forwarders at runtime. But I still prefer the original idea. Firstly, dynamic calls are likely to be a little slower. But secondly, and more importantly, I would have to change my generic class declaration when I want to enable this capability, which seems wrong.

So I still don't have a good reason for built-in dynamic calling in C#.

No comments: