Ayende @ Rahien

Refunds available at head office

Csc.exe and delegate inference, or: Why C# has awkward syntax

I just tried to to do a major revamp of Rhino Mocks' interface. It was intended to make it easier to work with C# 3.0 and use the smarter compiler to get better syntax.

I shouldn't have bothered. Take a look at this.

	public class TestCsc
	{
		public static void TestMethod()
		{
			Execute(Bar); // fail to compile
			Execute(delegate(int ia, string x) { }); // compiles fine
			Execute((int i, string x) => { return; }); // Compiles fine
			Execute((int i, string x) => { return true; }); // fail to compile
			Execute(Foo);// fail to compile
			Execute(delegate(int ia, string x) { return true; }); // fail to compile
		}

		public static bool Foo(int ia, string x)
		{
			return false;
		}

		public static void Bar(int ia, string x)
		{
		}

		public static void Execute<T, K>(Action<T, K> e)
		{
			
		}

		public static void Execute<T, K>(Func<bool, T, K> e)
		{

		}
	}
Annoyed.

Comments

Jay
03/20/2008 07:02 AM by
Jay

Maybe you were looking for Func<T, K, bool>?

ychebotarev
03/20/2008 07:22 AM by
ychebotarev

public static void Execute<T, K>(Func<bool, T, K> e)

should be

public static void Execute<T, K>(Func<T, K,bool> e)

:)

after that there will be errors only with

Execute(Bar);

Execute(Foo);

you can rewrite this as

        Action<int, string> bar_ptr = Bar;

        Execute(bar_ptr); // compiles fine

        Func<int, string, bool> foo_ptr = Foo;

        Execute(foo_ptr);// compiles fine

Here is big explanation why type inference didn't work in this case:

http://blogs.msdn.com/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx

But for me that was not very convincing.

Steve
03/20/2008 07:55 AM by
Steve

Lambda stuff is nice but I would love to see Boo DSL for rhino mocks :)

Frans Bouma
03/20/2008 08:39 AM by
Frans Bouma

Yes, this is pretty annoying. I ran into this as well when I wanted to introduce some types for prefetchpath specifications inside linq queries and wanted to get rid of the explicit generic argument specifications... IMHO it's a compiler flaw, no matter how many excuses they invent: they introduced syntactic sugar, then make the compiler deal with that in all cases.

Justin Etheredge
03/20/2008 12:06 PM by
Justin Etheredge

If you swap the bool on the end to Func<T, K, bool> then everything except for Execute(Bar) and Execute(Foo) works. And I agree with Frans, I have heard all the explanations about why it wouldn't work, but I wish they could have found a way to make it work.

Justin Etheredge
03/20/2008 12:23 PM by
Justin Etheredge

Let me also say that they could have enabled this for very simple scenarios such as the one you are dealing with. In the blog post by Eric Lippert referenced above he basically says that they could have done it in certain scenarios, but in other scenarios it would have been impossible. He said that they didn't want two different inference algorithms that produce slightly different results. While I am certainly not a compiler writer, that sounds like they are taking an idealistic approach and not a pragmatic one. The pragmatic approach would have been to try and make type inference work in as many different scenarios as possible, and have it fail when the resolution is unreachable.

Jay
03/20/2008 06:26 PM by
Jay

Execute((t, k) => Bar(t, k));

Execute((t, k) => Foo(t, k));

Krzysztof Koźmic
03/21/2008 07:05 AM by
Krzysztof Koźmic

I now your pain, earlier this week, I've been trying to come up with nicer, and more strongly typed ways to cope with events in Rhino.Mocks (strongly typed EventRaiser, event subscribtion and verification) and I failed miserably. I think I just gave up (at least for now). You can see the attempts at my blog.

And BTW, why are delegates so limited in cooperation with generics? :/ It's just annoying

Comments have been closed on this topic.