Wednesday, September 19, 2007

Parameterless Lambdas in C#

I'm liking Linq, but I think I like it more for the new language features it forced than for the query syntax itself. Lambdas and object initialization syntax - particularly collection initialization syntax - are extremely handy. Of course, I'm intentionally using them all I possibly can to find out where the cracks are. No doubt with experience I'll look at my current patterns as gross overuse. Nonetheless, it's fun. :)


I was writing some test code today in Visual Studio 2008 when I hit a good use case for lambdas. I wanted to execute a statement and compare the result to an expected value, but only if the expected value wasn't null. In that case I don't want to execute the statement at all, because it has unwanted side effects (specifically, it asserts something I know will be false).


I could have thrown a crateload of "if" statements in to check for null, but that wouldn't be very DRY. The solution I hit on was to use a parameterless lambda instead. It's passed to a method that evaluates the lambda if the thing it's being compared to isn't null. It works well. What I wanted to blog here was the syntax, because it wasn't immediately obvious to me, and it didn't really turn up anything in a few moments of Googling. So here it is for the record:


AssertEqualIfApplicable(

expected,

() => SomeMethodWithSideEffects(foo, bar))


private void AssertEqualIfApplicable(object expected, Func<object> actual)

{

if (expected != null)
{
Assert.AreEqual(actual());
}

}


So it's the "() =>" that defines a parameterless lambda. The syntax is a bit awkward, but not painfully so, IMO. The thing I especially like about this is that the lambda allows me to use lexical closures. Which is a fancy way of saying that foo and bar in my example above can be local variables, and their values will still be accessible when the lambda is invoked.


I must not have studied enough Lisp yet, because my reaction to this is "cool!" rather than "pfagh! Lisp has had that since 1827". Oh, and Keith, yes, I realize you are laughing at me, right now. :)

4 comments:

  1. C# has had support for closures with anonymous delegates since 2.0. And not all Lisps have closures (elisp, for example).



    If you really want to get lambdarific, you could make this more generic by making your null condition a predicate argument.



    static void AssertEqual<T>(T expected, Predicate<T> condition, Func<T> expression) {

    if (condition(expected)) {

    Assert.AreEqual(expected, expression);

    }

    }



    Then you could define your original method in terms of this variation, or you could have other less common conditions (expected != 0, expected != DateTime.MinValue, etc).



    static void AssertIfNonNull<T>(T expected, Func<T> expression) {

    AssertEqual(expected, e => e != null, expression);

    }

    ReplyDelete
  2. Yeah, I'm aware of closures in 2.0, although I think they don't really shine as much without lambdas. The syntax just isn't as nice, and Func<> helps avoid type bloat.



    I love the modification you suggest, though. :)

    ReplyDelete
  3. The other huge advantage lambdas in C# 3.0 have over anonymous delegates 2.0 is the inference of the return type. Previously the language would not infer the return type even if the delegate was as simple as 'delegate { return 1; }'.

    ReplyDelete
  4. Another great use for no-arg lambdas: pointing to a property getter (which was hack-city in 2.0).



    See http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1623765&SiteID=1

    ReplyDelete