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 :)