About me

Michael L Perry

Improving Enterprises

Principal Consultant

@michaellperry

User login

Delegates vs. Lambdas

What is the difference between these two lines of code?

bool anyNegative = numbers.Any(n => n < 0);

Vs.

bool anyNegative = numbers.Any(delegate(int n)
{
    return n < 0;
});

On the face of it, not much. These two lines do exactly the same thing. Yet there is an important difference.

The code inside of the lambda is an expression. The code inside of the delegate is a statement.

Expressions vs. statements

An expression computes a value, whereas a statement performs an action. In the above code, that action is to “return” a value. But the action could have been to change state. And therein lies the danger.

The order in which statements are executed is important. This is especially true if those statements change state. An assignment changes the state of a variable. A statement performed before the assignment sees the old value. A statement performed afterward sees the new value.

int m = 2;
Console.WriteLine(m);
m = 3;
Console.WriteLine(m);

Expressions, on the other hand, can be executed in any order, provided that they don’t change state. In the following code, it doesn’t matter if the program calculates x squared or y squared first. It will get the same answer because neither calculation changes state.

double x = 4.0;
double y = 3.0;
double h = Math.Sqrt(x * x + y * y);

Some expressions change state. For example, though the ++ operator increments a variable, it can be used as an expression. Also, a method called as part of an expression might in fact have some mutating side-effect. But in general, if we intend to change state, we will usually use a statement.

Delegates are commands; lambdas are queries

In Object-Oriented Software Construction, Bertrand Meyer defined a principle called “Command-Query Separation”. This principle encourages us to separate code that modifies state from code that computes values. A method that modifies state is a command, and should return void. A method that computes a value is a query, and should have no mutating side-effects.

If we follow this principle, then it will be difficult for us to write an expression that mutates state. If we avoid operators like ++ within our expressions, and we can’t call a void method, then we can safely assume that an expression is non-mutating. If our intent was to mutate state, we would have written a statement.

So if delegates contain statements, and the intent of a statement is to mutate state, then all delegates should be commands. Conversely, if lambdas contain expressions, and expressions can’t mutate state, then all lambdas should be queries.

To make your intention clear, use lambdas to compute values, and delegates to make changes.

public ICommand Delete
{
    get
    {
        return MakeCommand
            .When(() => _selected != null)
            .Do(delegate
            {
                _selected.Delete();
            });
    }
}


Good Advice

I try to minimize my degrees of freedom when programming. Thus, I would be naturally inclined to avoid delegates when possible. However, following conventions for clarity of intent is probably a more important thing to strive for.