Challenge: Striving for better syntax
Or, as I like to call them, yes another stupid language limitation. I did some work today on Rhino Mocks, and after being immersed for so long in DSL land, I had a rude awakening when I remembered just how much inflexible the C# language is.
Case in point, I have the following interface:
public interface IDuckPond { Duck GetDuckById(int id); Duck GetDuckByNameAndQuack(string name, Quack q); }
I want to get to a situation where the following will compile successfully:
IDuckPond pond = null;
pond.Stub( x => x.GetDuckById );
pond.Stub( x => x.GetDuckByNameAndQuack );
Any ideas?
Note that unlike my other challenges, I have no idea if this is possible. I am posting this after I got fed up with the limitations of the language.
Comments
Not possible unfortunately, you can make it work for the first scenario with a single argument but it will not work in a general case
Ideas? BooLangStudio ; )
The problem is in the overload resolution - how can the compiler determine which signature to select for a method group?
(Yes, in this case there is only 1 signature, but the general problem is "referring to a method by name").
Really, you have to give more context. The only way for the compiler to select an overload is to provide an actual invocation:
pond.Stub((string name, Quack q) => x.GetDuckByNameAndQuack(name, q));
It has been suggested that Expression<> can be used to do strongly-typed reflection. Perhaps something like:
public static class Reflector
{
public static MethodInfo MethodOf(Expression<Func> expression)
{
...Inspect expression body...
}
public static MethodInfo MethodOf<T, TResult>(Expression<Func<T, TResult>> expression)
{
...Inspect expression body...
}
public static MethodInfo MethodOf<T1, T2, TResult>(Expression<Func<T1, T2, TResult>> expression)
{
...Inspect expression body...
}
...And so on for other Func<> types...
...MemberOf, PropertyOf, and FieldOf would also be useful...
}
used like:
pond.Stub(Reflector.MethodOf(
(string name, Quack q) => x.GetDuckByNameAndQuack(name, q)));
Bryan,
Yes, I suspected that this is the case.
As for your suggestion, take a look here:
http://www.ayende.com/Blog/archive/2005/10/29/8176.aspx
Well there you go. I guess my Reflector class adds value because the type parameters can be inferred; you don't have to specify the return type.
But yes, the solution is the same. This would be moot if C# supported "infoof" or something to that effect.
You might find this of interest:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=345969&SiteID=1
Matt Warren explains why "infoof" isn't already part of the language.
Well, for the reasons that have been mentioned the best you can do is to have:
And then lots of overloads of Stub, to look like this:
I dont think that's the way to go. With current syntax I dont really thing there's a good solution for this.
I believe I can answer the question, if you clarify something
Given "pond.Stub( x => x.GetDuckByNameAndQuack);" compiling correctly, where would "name" and "q" come from?
So I gather that we are talking about making it compile without having to put something like this alongside the IDuckPond definition?
Pretty trivial to code generate, so I guess you are not interested in doing that?
I don't care if I have to do this, just as long as I don't have to do this per object that I am mocking
My question wasn't as clear as I'd like.
Given
pond.Stub( x => x.GetDuckByNameAndQuack);
presumably there will be a line which starts
Duck selectedDuck = ???????????
what's the end of that line?
There is not such line.
For the purpose of what I am talking about here, I don't care about actually calling this.
Another relatively obvious implementation that is very close to Krzysztof's suggestion but relies on generic parameter inference and not stub overloads:
d.Stub(x => (Func<int,Duck>) x.GetDuckById);
d.Stub(x => (Func<string, Quack, Duck>) x.GetDuckByNameAndQuack);
public static void Stub<T, U>(this T obj, Func<T, U> func) { }
Again, not an ideal solution I know.. just throwing it out there...
So we have an implementation, without a (given) purpose. That's kinda like says "I want to walk North, but there's a wall in the way". The real question is "where do you want to go?" then we work on how to get there...
Ayende - please elaborate your problem. People here are having different understandings.
No, the purpose here is to get this to compile, because that it is the only hurdle on the way.
I don't want to have any external issue with the issue at hand.
Once you get that to compile, we can discuss how we can use this feature, but until we do, there is not point in moving on
Sashi,
There is nothing to elaborate. I want a way to get the above code to compile, that is all.
Oren,
I see what you are going for now. The code as you have written it will never be valid because it doesn't actually describe your intent.
From the compiler's perspective, you are missing information: the parameters which determines the method's signature. No sane compiler would attempt to "guess" which one you meant to invoke.
The point is that a method name by itself doesn't mean what you want it to mean. Your code is akin to walking into the house of a family and asking for a particular person by last name only. Everyone is going to look at you funny until you tell them something more.
would you accept:
IDuckPond pond = null;
pond.Stub(x => x.GetDuckById, default(int));
pond.Stub(p => p.GetDuckByNameAndQuack, default(string), default(Quack));
Implemented by:
Bryan,
Yes, I understand what the problem is.
I am just not happy about it.
Jacob,
That is probably the best solution, but I don't like it.
Yeah; I can understand that.
This one's even more verbose (and pretty silly)--but is somehow charming:
IDuckPond pond = null;
pond.Stub(x => x.GetDuckById, id => default(int));
pond.Stub(x => x.GetDuckByNameAndQuack,
Implementation:
public static void Stub<T, T1>(this T instance, Func<T, Func<T1, object>> fn,
public static void Stub<T, T1, T2>(this T instance, Func<T, Func<T1, T2, object>> fn,
Oren,
I guess what I'm wondering is: without resorting to arbitrary resolution, how could the problem of "method reference by name only" be different? Not just in C# land, in general.
What is the intent behind your proposed syntax? It doesn't read as anything meaningful to me. How would you state your intent in natural language?
Bryan,
I am try to say "when you can method A, regardless of its parameters".
I would handle this by allowing it if there are no overloads, and require disambiguation only if it is neccesary.
Ok, so the general problem is "overload resolution with less-than-sufficient information."
Eric Lippert addressed this issue; return type inference on method groups is what gets you. He says it better than I can:
http://blogs.msdn.com/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx
The final stance seems to be that the rules you are suggesting, Oren, cause confusing overload resolution rules which would violate the Principle of Least Surprise and be a source of subtle bugs.
I would be interested to hear your thoughts on that article.
Hey Jacob I like that last one, I agree even though its more verbose its nice. Maybe because it reminds me of passing parameters to a ruby method using a hash.
Further to the link that Bryan supplied, Eric Lippert just wrote a post today to follow up on this issue.
http://blogs.msdn.com/ericlippert/archive/2008/05/28/method-type-inference-changes-part-zero.aspx
Bryan,
From my perspective, this is throwing the baby with the bathwater.
If it it possible to make a best-effort attempt, I think that it should be done.
Sure, there would be pathological cases, but to block the feature because we can't handle them seems excessive to me.
I agree. I was happy to read the post by Anonymous indicating the entire enterprise is being reworked.
Or rather, the post by Eric Lippert referred by Anonymous.