Dynamic type inference and surprising possibilities

There have been mutterings about the fact that I haven’t been blogging much recently. I’ve been getting down to serious work on the second edition of C# in Depth, and it’s taking a lot of my time. However, I thought I’d share a ghastly little example I’ve just come up with.

I’ve been having an email discussion with Sam Ng, Chris Burrows and Eric Lippert about how dynamic typing works. Sam mentioned that even for dynamically bound calls, type inference can fail at compile time. This can only happen for type parameters where none of the dynamic values contribute to the type inference. For example, this fails to compile:

static void Execute<T>(T item, int value) where T : struct {}

dynamic guid = Guid.NewGuid();
Execute("test", guid);

Whatever the value of guid is at execution time, this can’t possibly manage to infer a valid type argument for T. The only type which can be inferred is string, and that’s not a value type. Fair enough… but what about this one?

static void Execute<T>(T first, T second, T third) where T : struct {}

dynamic guid = Guid.NewGuid();
Execute(10, 0, guid);
Execute(10, false, guid);
Execute("hello", "hello", guid);

I expected the first call to compile (but fail at execution time) and the second and third calls to fail at compile time. After all, T couldn’t be both an int and a bool could it? And then I remembered implicit typing… what if the vaue of guid isn’t actually a Guid, but some struct which has an implicit conversion from int, bool and string? In other words, what if the full code actually looked like this:

using System;

public struct Foo
{
    public static implicit operator Foo(int x)
    {
        return new Foo();
    }

    public static implicit operator Foo(bool x)
    {
        return new Foo();
    }

    public static implicit operator Foo(string x)
    {
        return new Foo();
    }
}

class Test
{
    static void Execute<T>(T first, T second, T third) where T : struct {}

    static void Main()
    {
        dynamic foo = new Foo();
        Execute(10, 0, foo);
        Execute(10, false, foo);
        Execute("hello", "hello", foo);
    }
}

Then T=Foo is a perfectly valid inference. So yes, it all compiles – and the C# binders even get it all right at execution time. So much for any intuition I might have about dynamic typing and inference…

No doubt I’ll have similar posts about new C# 4 features occasionally… but they’re more likely to be explanations of misunderstandings than deep insights into a correct view of the language. Those end up in the book instead :)

9 thoughts on “Dynamic type inference and surprising possibilities”

  1. I’m somewhat concerned too about the complexity vs. value that C# 4 brings. It feels to me like C# 3 with all of its LINQ supporting additions was a much better prospect. Ian Carmichael, CLR guru, points out that one of the major points of IL is to enable language interop, and yet in VS you still can’t, in the IDE, easily add say a F# file to a C# project, or more to the point a C# source file to a C++/CLI project. One *can* do these things, but it involves command line tools – which most people seem to walk in fear of. I’d much rather Microsoft took advantage of promoting language interop rather than adding more and more features to each respective managed language in a attempt to make them all the same. C# does not need to be VB.NET, VB.NET is *really* good at being VB.NET. Hmmm.

    When do you think you’ll start posting MEAP chapters of the 2nd edition Jon? I can’t wait to read them!

    Kind regards,

    Tom

  2. @Tom, David: I agree that there isn’t much value for *many* developers in terms of “dynamic”. (I’m much more convinced by named arguments and optional parameters.)

    However, where it *is* useful, I think it’ll be very useful – and I’m really impressed by the quality of the implementation, as far as I’ve seen it so far. I think of it as a bit like “unsafe” – not very useful to most people, but great where you need it. I’ll be making that point fairly forcibly in the book :)

    As for the 2nd edition chapters – I’m still writing the first new chapter of it, but once that’s done I’ll see what I can do. Hopefully not too long…

    Jon

  3. shoot… I just bought the 1st edition of your book! :)

    When is the target release of the 2nd ed?
    And what will the value add be for those who have the 1st ed?

  4. Rafferty,

    I don’t expect the 2nd edition to be released until at least Q1 2010. I’m hoping there’ll be ways of existing owners getting hold of the new material (at least in electronic form) cheaply too, although nothing’s confirmed on that front yet.

    As for the added value: I’ll be revisiting the existing material, but I don’t expect *very* much to change. The main differences will be material about C# 4: dynamic typing, named arguments and optional parameters, and COM improvements. There will also be a chapter on Code Contracts and Parallel Extensions, as both of those can change how one uses the language significantly.

  5. “I think of it as a bit like “unsafe” – not very useful to most people, but great where you need it.”

    I agree that they are very similar in concept, but unfortunately they are not at all similar in implementation. Using “unsafe” in C# requires the code to be in an unsafe block, AND requires the /unsafe compiler switch. You have to be VERY intentional in order to use unsafe, which I consider to be a good thing.

    All dynamic requires, on the other hand, is the dynamic keyword, which can be substituted for var and hardly looks any different. I guarantee you that a year from now when I am interviewing candidates and ask them about the difference between dynamic and var, a huge percentage of them are going to claim that there is basically no difference.

    In my opinion all of this is setting developers up for failure; it is the exact opposite of the Pit of Success. And once it’s done, it can’t be undone, which means we are going to be paying for this design mistake for many years.

Comments are closed.