Lambda expressions are powerful tools that allow you to create succinct inline functions. However, without proper care they can quickly descend into an unreadable mess. While there are several ways that a lambda expression can become messy, this article will only address the naming conventions used for the expression’s parameters. Here are the two different conventions:
The single letter
When lambda expressions were first introduced, all of the code examples that were provided used single letters for their parameter names. I believe this was done to show the new compact syntax provided by lambda expressions.
In simple cases, a single letter is all that is needed:
Enumerable.Range(0, 10)
.Where(i => i > 5)
In other cases a single letter can easily hurt the readability of the expression:
Enumerable.Range(0, 10)
.Aggregate((m, n) => m + n)
In this example the meaning of the parameter names are hard to determine because we have used single letters for multiple parameters. This prevents us from knowing which parameter represents the sequence item and which parameter represents the aggregated state. In the first example it was easier to deduce the meaning of i because a single parameter indicated a single item in the sequence.
The longer and descriptive
After some time, I began to notice a shift in style (mainly in blogs and code that I read) – perhaps in response to the confusion caused by the single letter approach. People began to give more expressive names to their lambda expression parameters, even at the expense of the brevity of the expressions themselves.
Our Aggregate example from above becomes much easier to understand using this newer style:
Enumerable.Range(0, 10)
.Aggregate((aggregated, current) => aggregated + current)
However this style applied to our first example (using Where) adds length to the expression without adding much else:
Enumerable.Range(0, 10)
.Where(number => number > 5)
So what is the right way?
As in most things in life, the right way lies somewhere in the middle. Our first responsibility when it comes to naming conventions is to follow a set of rules that maximizes the readability of the code for those who will read it later. You do not want to write expressions that are cryptic and not easily understood in a single pass. You also do not want to write verbose expressions that are impossible to comprehend in their entirety.
Sometimes a single letter will suffice and other times a more expressive name is better. Here is a good rule of thumb:
If the expression requires one parameter then use a single letter. If the expression requires more than one parameter then use a more expressive identifier
Other thoughts
Another convention I have seen is the use of a single underscore as a placeholder for variables that are ignored in the body of the expression:
foo.SomeEvent += (_, args) =>
{
// ...
};
In this example we are handling a standard EventHandler, but we don’t use the Object sender parameter. Rather than clutter the area with a name that looks meaningful, but isn’t used, it is better to use a single underscore as a placeholder. This satisfies the compiler’s requirement for an identifier, while indicating to the reader that the parameter is unused.
If in the event you do not need any of the parameters, rather than use placeholder identifiers, remember that C# 2 gave us the ability to create delegates that ignore the parameters altogether:
foo.SomeEvent += delegate
{
// ...
};
Here’s to better parameter names in lambda expressions! Let’s try to write code today that we can all read tomorrow.