I love lambdas and I'm pretty sure they solve every problem imaginable. Why just the other day my daughter painted her face with leopard spots, using a Sharpie pen, and I said to myself "Rob(x=>x.Beer("immediately"))" and all of a sudden the world was a brighter place...
Lambdas Are A Party In One Line
This was overheard on Twitter today - a conversation between Kevin Dente and Scott Hanselman RE Lambdas and mocking frameworks:
The benefits [of using Lambdas], for me, are two fold, 1 it looks more like I think, 2 it doesn't require knowledge of the different kinds of mocks
I agree with Scott completely - once you use them a few times, you GET them, and what they can do. And then you kind of go Lambda crazy (where I am now). There's lots to read about them if you don't know them very well:
Free Your Mind (or at least Delegate It)
Lambdas allow you to do some cool things - such as pass a reference to a method as an argument - constructing it on the fly. Yes, you can do this with Delegates - but that takes some code. Lambdas allow you to terse that up a bit and also get a bit more free-form.
If I have a method, such as this:
public void ActionLink<T>(Expression<Action<T>> action) where T:Controller{ .... }
I've created a delegate to handle the passed-in method using the plain Vanilla "Action" delegate that lives in System. I then slap a generic type argument on there, saying that "T" must be a Controller - in that I've now restricted the argument to take a Controller Method. This is all the code I had to write to handle this.
The final step is to wrap that with Expression (using System.Linq.Expressions) - this means that you can use a Lambda to specify the delegate and not have to wire up your own.
This is really important - as now you have a very type-safe, descriptive method signature when you call ActionLink<T>:
string link=ActionLink<HomeController>(x=>x.Index());
Note that I don't have to create a delegate referring to Index() anywhere - this is "on the fly" so to speak and it makes coding a lot more flexible.
I've Got Lambda Fever
I'm driving Phil and Eilon crazy. They're good sports and definitely listen to my input, but then they got me this T-Shirt, which Phil told me was probably causing Stack Overflow in my case:
Hrrmph. Well it's soft, at the very least.
I'd love to see lambdas everywhere, but that's me. I know that not everyone's brain works that way - so I'd love your feedback. Do you agree with Scott? Or are these things really nerdy? Do you find Lambdas helpful or cumbersome?
Technorati Tags: aspnetmvc
Oooopppsss... Wait, sorry. I guess I'm a little carried away with them too!
-------------------
Honestly I think they are earth-shattering, but mainly because there is a change in my thinking and approach to a problem. I think they are a little more declarative which -- for awhile -- I didn't find all the interesting/useful, but now as I wrap my head around this new type of thinking, it's kind of fun, and seems to be improving my code's readability.
2 years from now, I may be saying that they suck, but at the moment they are truly cool.
p => p.age
vs.
function(p) p.age
I agree with Kevin that neither is a "totally natural syntax for expressing this stuff." The VB version is worse than C#'s in this respect.
--rj
Will you elaborate on this statement?
"The final step is to wrap that with Expression (using System.Linq.Expressions) - this means that you can use a Lambda to specify the delegate and not have to wire up your own."
I thought you could just pass a lambda using Action without wrapping it in an expression? Or maybe my point of confusion was that by "wire up your own" you _didn't_ mean "declare a delegate"?
Thanks,
Troy
Seriously loving the lambdas and the expression tree thing makes for some serious fun
I would be grateful if you shared this solution: twitter.com/.../774668887
Hey Josh :) - getting ready to load up my Graffiti post and how I did it - but to answer you...
1) Get ISAPI rewrite (lite) from Helicon.
2) This is your Rewrite Rule: RewriteRule /(\w.*)/(\d.*?)/(\d.*?)/(\d.*?)/(\w.*) /$1/blog/$5
3) This assumes all your posts are in the "blog" category and
4) They are off the root.
Lemme know if you need more - my post is coming tomorrow.
what would you put on a lambda tshirt exactly?
Thanks, dude! Looking forward to the post.
@Rob,
I will try to flesh out my "strong statements" in a blog post at some point. However, to address my point about lambdas being a clumsy way to get a strong reference to a method:
Lambdas represent expressions, that is, executable code fragments. That's why they map so well to expression trees. But in the case of your ActionLink method, what you care about is not an expression, not executable code, but just a strongly typed reference to a single method, independent of any particular instance. So you have to parse the Expression that the lambda has been converted into, looking for the method that is being called in the executable code. But you can't guarantee that the Expression actually represents a single method: it could be any executable code fragment which matches the Action<T> signature (takes one argument and returns void). For example, how would your ActionLink method handle the following call?
string link = ActionLink<HomeController>(x => Math.Abs(2));
Presumably it would fail at runtime when you try to parse the expression, defeating the point of the "strongly typed" lambda, because lambdas are only strongly typed in terms of their contract, not their content. What you really care about is the content.
Wouldn't it be great if C# had language support for strongly-typed open delegates? How perfect would that be for your situation? But, unfortunately, no such support exists. So you have to hack around that missing feature using lambdas, even though they really aren't well suited for the task.
While .NET has a leg up on many other popular languages/frameworks in terms of reflection, its support for strongly-typed reflection has previously been non-existent. Now we have lambdas, which are a useful but very limited form of strongly-typed reflection; but since they are the only strongly-typed reflection we have available to us, we are forced to make do.
My point is this: this post is taking a hack using lambdas and extolling it as a virtue. That's just not how I want to approach software development. Lambdas allow us to do certain things more easily and more cleanly than we could before, and that's great. But just because my square peg is barely flexible enough to squeeze into my round hole, doesn't mean I wouldn't rather have a round peg to begin with. Lets appreciate lambdas for what they are, not for what we have to force them to be due to lack of other options.
@David - thanks for dropping by again :). I disagree with you a bit here, but I understand your point. Let me see if I can clear this up:
>>>But you can't guarantee that the Expression actually represents a single method: it could be any executable code fragment which matches the Action<T> signature<<<
Actually you can guarantee it - ActionLink<T> has a "where:" on it and that where is set to "Controller".
The method only takes "Expression(Action<T>)" which makes sure that what you pass in is a method on your controller.
So the code you wrote wouldn't compile - which is the point :).
Moreover this WOULD compile:
ActionLink("myController", "four score and seven methods ago...");
In that, you can see why I like Lambdas :).
>>>Wouldn't it be great if C# had language support for strongly-typed open delegates? How perfect would that be for your situation?<<<
And now we're getting somewhere. This, my friend, is the point of the post and also ActionLink<T>. I just don't think I explained it clearly :).
>>>Lets appreciate lambdas for what they are, not for what we have to force them to be due to lack of other options<<<
Fair enough, but to be honest I think you might be missing an opportunity to see a really cool language feature here. I don't think I'm abusing lambdas - in fact (a fun side note) that code (for Action<T>) was actually written by Anders :). I didn't have much to do with it :):).
How is this sounding?
@Rob,
I am aware of the where clause. But it only guarantees that the delegate that is parsed into an Expression takes a parameter of a given type; it does NOT guarantee that parameter is ever referenced, which is required for your ActionLink method to work.
"So the code you wrote wouldn't compile"
Did you try my code? It compiles just fine for me, given the method signature in your post (except that you have to change "public void T>" to "public string ActionLink<T>", which is also true for the example in your post).
"Moreover this WOULD compile:
ActionLink("myController", "four score and seven methods ago...");"
It doesn't compile when I try it. I don't see why you think it would.
Since you say my code doesn't compile, and I say your code doesn't compile, I think its safe to say that we are talking past each other somehow. Can you clarify why you believe that a call with two string arguments to a method with a single Expression argument would compile? Maybe if we can resolve that then we can continue with the rest of the discussion.
@David: I stand corrected - the code will compile (unfortunately) however it does throw a runtime since there is a type violation (late-bound, apparently).
This, however, does compile as well:
<%=Html.ActionLink("linktext","action","controller")%>
And worse yet, will NOT throw an error, even if said controller/action doesn't exist.
Moreover, the ActionLink<T> bits are smart enough to ask the routing table was route we have set up for that action/controller pair, so I don't need to worry about it :).
So, what you call a "hack" I maintain is very useful.
>>>ActionLink("myController", "four score and seven methods ago...");
In that, you can see why I like Lambdas :).<<<
I have not actually used the MVC framework; I guess there are other overloads of ActionLink other than the one you provided which would allow the string version to compile. However, it is obviously not strongly typed; it is similar to data-binding or other string-based binding which can only be resolved at runtime. It also obviously has nothing to do with lambdas. I am confused as to why you think that the string version would demonstrate to me why you like lambdas.
Let me be clear: its not that I don't like lambdas. I think they are very useful for a certain class of problems. But like most new language features, some people have become so enamored with them that they try to solve every problem with that feature, even when it is not really appropriate (what Eilon did with anonymous types in the MVC framework is probably the most spectacularly awful example I have seen of this syndrome).
I'm not saying that the Expression version is any worse than the string version; it is probably better in some ways. But that does not mean that it is not still a hack around another missing feature which would actually fit the need (strongly-typed member reflection), just like the string-bound version is.
@David: I think we can wrap this dialog up by agreeing to disagree. To me, the language works for me, not me for it so I feel absolutely free to bend it how I please :). You see that as a hack, I see it differently...
>>>what Eilon did with anonymous types in the MVC framework is probably the most spectacularly awful example I have seen of this syndrome<<<
This, my friend, was all ScottGu. Eilon/Phil were the ones who insisted that they shouldn't be there. You decide who's right :).
>>>But like most new language features, some people have become so enamoured with them that they try to solve every problem with that feature, even when it is not really appropriate<<<
I agree.
When you've just been given a brand new shiny hammer, everything looks like a nail again. :)
Anonymous types really shouldn't exist for very long at all. Typically, only the scope of a single function. If it gets passed to a second function, it should get dismantled and then forgotten about (like the RouteValueCollection ctor).
But anonymous types made my syntax easier to read and I wrote less code. Now, with RouteValueCollection, my code wraps onto the next line :( but i've got a dictionary which is actually useful :).
It's true that lambdas don't allow you to do anything we couldn't already do with anonymous delegates. (If you can't get the expression tree of a simple delegate, someone has missed a trick).
But now I've got lambdas i'll probably never use anonymous delegates again, cos the syntax is so clean and easy to read. I can use them directly as method arguments and not feel dirty.