Hanalei, Hawaii 9/2/2010
438 Posts and Counting

My Personal Lambda Crusade

Monday, March 17, 2008 -

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:

try_try_again

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:

Related


Gravatar
adminjew - Monday, March 17, 2008 - How does Lambdas work with LOLCode?
Gravatar
Giovanni Bassi - Monday, March 17, 2008 - I love them! Really, It feels like they are freeing my mind. They give you a total new way of thinking about how you are going to implement things. Just as you described.
Gravatar
Kevin Dente - Monday, March 17, 2008 - Quoting a Twitter conversation in a blog post? YOU BASTARD!!! :P Since you're making me look all close-minded and 2005 here, I'll just say this. I agree that lambda's are cool and really useful. My point was that we still don't have a totally natural syntax for expressing this stuff. Lambda's may be an improvement, but I ultimately I hope we can do better.
Gravatar
Jon Limjap - Monday, March 17, 2008 - I love lambdas, problem is my teammates are terrified even of anonymous methods. Still working towards convincing/teaching them. :)
Gravatar
David Nelson - Tuesday, March 18, 2008 - I really don't get what everyone is so gung-ho about. Sure, lambdas are nice; they are an improvement over anonymous methods, which were an improvement over normal delegates. But they're not earth-shattering or anything. As you say, a good thing about lambdas is that they can be turned into expression trees. But the reality is, there is nothing stopping the compiler from turning any method into an expression tree (in fact, being able to turn arbitrary methods into expression trees would be extraordinarily useful in certain cases). The C# team simply chose to implement that functionality only with lambdas.
Gravatar
Rob Conery - Tuesday, March 18, 2008 - @kevin - oops. I didn't mean to misquote you. Doh! I'll ammend the post here to make sure the context is understood. Dammit i hate when that happens! I wouldn't have said 2005 - maybe Feb of 2006.... @David - they are, actually, earth-shattering when you consider what's possible. Think about it - how would you pass a strongly-typed reference to a method?
Gravatar
tgmdbm - Tuesday, March 18, 2008 - I love lamp too. ... I mean lambdas. I'd love to see this do what I expect. ;) var query = from p in db.Products group p by p.Category .... p.Id, p => p.Name ) %>
Gravatar
tgmdbm - Tuesday, March 18, 2008 - ... <% Html.Select( "mySelect", ViewData.Query, p => p.Name, p => p.Id ) %> [unmangled and corrected order of Name and Id]
Gravatar
Jay Kimble - Tuesday, March 18, 2008 - Let all the non-infidels who don't use Lambda's die...

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.
Gravatar
Kevin Dente - Tuesday, March 18, 2008 - *Grumble Grumble* Generics? Automatic properties? In my day we hand coded our BindingLists. Lazy punks. *Grumble Grumble*. It's all good, brother. I'm just giving you a hard time. No offense taken.
Gravatar
Roger Jennings - Tuesday, March 18, 2008 - I like lambdas a lot more in C# than VB:

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
Gravatar
Troy DeMonbreun - Tuesday, March 18, 2008 - @Rob,

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
Gravatar
mike kidder - Tuesday, March 18, 2008 - Sesame Street came to mind: Mmmm.... Lambdas, Lambdas, Lambdas, me loves Lambdas!
Gravatar
Joel Cochran - Wednesday, March 19, 2008 - I had the same question as Troy: I am unclear as to what Expression buys you? I have created several Extension methods that take an Action as a parameter, and my Lambda code looks just like yours. What am I missing? As for the rest, I agree that Lambdas are great. Once I got over the "but how does it know what 'x' is???" type of questions, they made perfect sense to me. Now I find them very readable, and I think they will actually prompt more people to use delegate functions. One of my favorite tricks is to use the Func generic delegates to create local named methods. If you ever create private class methods that are only called by one other method (usually done to clean up a complex method), then you will love this approach.
Gravatar
Mike Minutillo - Wednesday, March 19, 2008 - *rainman mode* Lambdas...yeah...definitely lambdas

Seriously loving the lambdas and the expression tree thing makes for some serious fun
Gravatar
Andrew Wilson - Wednesday, March 19, 2008 - At work yesterday I was trying to explain lambdas to someone, so I wrote a Dane Cook joke out in a lambda function. Bee.onAttacking = (o, e => ((Bee)o).IsFacePunched = true; ) Later that evening I was thinking that I really should give bees the benefit of the doubt and only punch them in the face if the EventArgs.Target was directed at me... maybe add a switch in there or something... but I remembered how much I hate bees and wanted them all to be punched in the face. :) -Andrew
Gravatar
David Nelson - Saturday, March 22, 2008 - "...how would you pass a strongly-typed reference to a method?" You mean...use a delegate?
Gravatar
Rob Conery - Saturday, March 22, 2008 - @David: "...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."
Gravatar
David Nelson - Saturday, March 22, 2008 - @Rob, I agree. As I said in my first comment, lambdas are an improvement over anonymous methods, which are an improvement over delegates to named methods. However, as I also said in my first comment, a little bit of easier syntax hardly makes lambdas earth-shattering.
Gravatar
Rob Conery - Saturday, March 22, 2008 - @David: Fair enough - though I'm not sure what your point is other than to temper my enthusiasm - which is fine, but simplifying my statements does nothing but make you sound like an grumpy fart :). So - do this for me. The method signature above is for creating a Url from a Controller/Action. Write me that code using Delegates and we can take it from there.
Gravatar
David Nelson - Saturday, March 22, 2008 - My point was to respond to your request for feedback. "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." I didn't realize that you only wanted feedback that wholeheartedly agreed with you, and that any other response immediately qualified someone as "grumpy". If you are not interested in other viewpoints, perhaps you shouldn't solicit feedback in your posts? As you undoubtedly know, the ActionLink method cannot currently be rewritten in a "type safe" way without lambdas. On the other hand, a lambda is a pretty clumsy way to get a strong reference to a method. An "infoof" operator would be much more direct, and easier to use from within the implementation of ActionLink than an expression tree. I'm sure I have seen dozens of requests for such an operator in Connect over the past few years, but the C# team has not seen fit to implement such a simple feature. That's not to say that lambdas are useless; far from it. But like many new language features, they are being touted as the solution to all sorts of problems for which they are not particularly well suited. If lambdas get you fired up, that's great; I prefer to save my enthusiasm for things which make a significant impact on my productivity, and lambdas just don't fall into that category for me. Of course, that is just my opinion. You obviously disagree with it; that's fine with me. I didn't realize that such disagreements required name-calling, but I'm sure I can dredge up a few insults if you feel it would be appropriate.
Gravatar
Rob Conery - Sunday, March 23, 2008 - @David: Thanks for the reply... >>>As you undoubtedly know, the ActionLink method cannot currently be rewritten in a "type safe" way without lambdas.<<< Yes - that's why we did it. >>>On the other hand, a lambda is a pretty clumsy way to get a strong reference to a method.<<< Tell me why you think this - not in a debate sense, but the "why" is important to me. You made two strong statements here: >>>But like many new language features, they are being touted as the solution to all sorts of problems for which they are not particularly well suited<<< >>>I prefer to save my enthusiasm for things which make a significant impact on my productivity, and lambdas just don't fall into that category for me<<< And what I'm looking for in terms of feedback is the detail - not the statement (if that makes sense). Please, tell me why you feel this way with some examples. This is not a challenge - it's why I wrote this. >>>I didn't realize that such disagreements required name-calling, but I'm sure I can dredge up a few insults if you feel it would be appropriate.<<< >>>I didn't realize that you only wanted feedback that wholeheartedly agreed with you<<< Can we just avoid this bantering thing please? I'll keep the jokes to myself :p
Gravatar
Jim Zimmerman - Sunday, March 23, 2008 - My kids have used the sharpie on the face several times and you will not believe what works getting it off, milk. Yep that's right, comes off in minutes. Makes you wonder about what is in milk though. :)
Gravatar
Josh Stodola - Tuesday, March 25, 2008 -

I would be grateful if you shared this solution: twitter.com/.../774668887

Gravatar
Rob Conery - Tuesday, March 25, 2008 -

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.

Gravatar
VIjay Santhanam - Tuesday, March 25, 2008 -

what would you put on a lambda tshirt exactly?

Gravatar
Josh Stodola - Wednesday, March 26, 2008 -

Thanks, dude! Looking forward to the post.

Gravatar
David Nelson - Thursday, March 27, 2008 -

@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.

Gravatar
Rob Conery - Thursday, March 27, 2008 -

@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?

Gravatar
David Nelson - Thursday, March 27, 2008 -

@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.

Gravatar
Rob Conery - Thursday, March 27, 2008 -

@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.

Gravatar
David Nelson - Thursday, March 27, 2008 -

>>>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.

Gravatar
Rob Conery - Friday, March 28, 2008 -

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

Gravatar
tgmdbm - Friday, March 28, 2008 -

>>>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.

Gravatar
yelinna - Wednesday, May 06, 2009 - ¿while(!(succeed=try()));? I prefer: while(try()!=succeed);