Lambda variable names - to short name, or not to s

2019-03-17 07:38发布

问题:

Typically, when I use lambdas, I just use "a, b, c, d..." as variable names as the types are easily inferred, and I find short names to be easier to read. Here is an example:

var someEnumerable = GetSomeEnumerable();
var somethingElseList = someEnumerable.Select(a => a.SomeProperty)
                                      .OrderBy(a => a.SomePropertyField);
var someDictionary = somethingElseList.ToDictionary(a => new SomeClass(a.Prop1),
                                                    a => a);

Some question this naming, and would prefer to see long typed out names, like this:

var someEnumerable = GetSomeEnumerable();
var somethingElseList = someEnumerable.Select(importantObj => importantObj.SomeProperty)
                                      .OrderBy(objsInfo => objsInfo.SomePropertyField);
var someDictionary = somethingElseList.ToDictionary(theInfoId => new SomeClass(theInfoId.Prop1),
                                                    theInfoId2 => theInfoId2);

Since the scope is so narrow (between the parens), unless you're getting stupid and nesting them, I find it easier to read short names.

Without getting caught up in the silly naming examples I used above, what is the general consensus on Lambda variable names? To short name, or not to short name?

回答1:

The way I usualy do it depends on the collection you're enumerating over. If the name of the collection implies what type the lambda parameter will be, then I just go with the single letter, however if the collection isn't as descriptive, then I'll use a word.

IE:

myCollection.Where(person =>....); //non descriptive collection name

myPeopleCollection.Where(p=>...); // descriptive collection name


回答2:

I try to use single-word but meaningful names. So I would tend to use "person" rather than "p" but wouldn't go for "newlyAddedPerson".

This goes for query expressions as well - I may well violate this in quick throwaway examples, but I don't generally like:

from p in source
where p.Age > 10
select p.Name;

I'd far rather see

from person in source
where person.Age > 10
select person.Name;


回答3:

I like the shortname thing. I do that all the time. I mostly use i,y,x in lambdas, but I use a,b,c,d in sql.



回答4:

I'd say I agree with BFree. That, for me, it will depend on the context, but I always try to make it as 'concise' as possible. Notice I say concise, and not terse or short.

Here's two examples in the LISP dialect Clojure:

user=> (def names ["ryan" "bob" "tom" "tim"])
#'user/names

user=> (filter (fn [name] (.startsWith name "t")) names)
("tom" "tim")

For those that don't know Lisp/Clojure, my lambda is the argument to the function 'filter'. That is, "(fn [name] ....)". I chose to use 'name' here because it's short but describes exactly what I'm working with. However, I think an 'a', 'i', 'x', etc would be just as readable.

user=> (def odds (iterate (fn [n] (+ n 2)) 1))
#'user/odds

user=> (take 5 odds)
(1 3 5 7 9)

Here, I just use 'n' to stand for 'number'. I think 'number' would be OK too, but is slightly too verbose for my taste.

I certainly would NOT use the names 'nameOfPerson' or 'previousOddNumber'. That's just WAY too much information. I also try to keep types out of my names most of the time, e.g. 'nameString'. I find stuff like that, most of the time, to be superfluous information.

Personally, I think extra verbose names like that tend to stem from the idea that it helps document the code. It is especially prevalent in languages like Java/C# it seems. I think this could be argued both ways, depending on the programmer's style. However, the more verbose the name, the more tight (read brittle) the code can become. If my name is very specific, and it's a function changes often, then chances are the name will have to change a lot too. Eventually, the DEV might get lazy and you'll end up with a name that doesn't actually describe what the variable is used for. This is not a problem, if and only if the programmer doesn't assume the name is correct. Granted, this would probably be figured out quickly during compilation (because the programmer will try to divide two strings or some such thing), but it can cause wasted time and confusion in larger projects.

I would also argue for conciseness because of screen real-estate. I still try to wrap my rows at 80 columns wide, and that's hard when 'myVaraibleNameIsAsLongAsAParagraph'.

Ultimately, I think it's always going to come down to compromise. So they don't like 'a', but maybe they can agree that you should strive for one-word names like 'person' or 'number', and avoid that awful camel case.

Sorry for the book.



回答5:

Our team does not allow single letter variables, not event in lamdas.

What we find is, just like in TSQL, the longer the code lives the more confusing it gets. As far as lambda's

We would do something like this:

people.Where(personFound => personFound.FirstName.Contains("blah!"));

That way the next dev will not have to look at

people.Where(p => p.FirstName.Contains("blah"));

It seems readable, but it always does at first

What about a join

citizenShip.Join(people, c => c.personid, p => p.persoinid, (p, c) => new { p.FirstName, c.IsCitizen})
.Where(pc => pc.FirstName.Contains("blah");

the same with variable names

citizenShip.Join(people, 
                 citizenToJoin => citizenToJoin.personid, 
                 personToJoin => personToJoin.persoinid, 
                 (joinedPerson, joinedCitiznship) => 
                     new { joinedPerson.FirstName, joinedCitiznship.IsCitizen})
.Where(personAndCitizenshipFound=> personAndCitizenshipFound.FirstName.Contains("blah");

Oh but this is confusing and ugly. Just use differenct letters so it less confusing

citizenShip.Join(people, 
                 c => c.personid, 
                 p => p.persoinid, 
                 (jp, pc) => 
                     new { jp.FirstName, jc.IsCitizen})
.Where(pc => pc.FirstName.Contains("blah");

Still confusing, but now its worse. So we break the lambda up so we refactor for readability

var peopleWithCitizenship = citizenShip.Join(people, 
                                             citizenToJoin => citizenToJoin.personid, 
                                             personToJoin => personToJoin.persoinid, 
                                             (joinedPerson, joinedCitiznship) => new { joinedPerson.FirstName, joinedCitiznship.IsCitizen});

var peopleWithCitizenshipFilteredByName = peopleWithCitizenship.Where(personAndCitizenshipFound=> personAndCitizenshipFound.FirstName.Contains("blah"));

This is not a perfect example but make the code readable with very little insider knowledge. We find this exposes complex code(lambda) which needs to be broke up into smaller chunks.



回答6:

It may be asking a lot to ask a question for 'consensus' on 'naming'. :)

I agree that 'the importance of a good name' is proportional to the scope of the name. Jon Skeet's answer of preferring

from person in source ...

is compelling, but if the name is used a lot and especially if the input is better named, I think I prefer

from p in persons ...


回答7:

I go with one, two or three letters, which form an abbreviated representation of the object in question.

Persons.Where(p => ...)
AnalysisCode.Where(ac => ...)


回答8:

As a general rule, I think the more explicit you are with variable/object/method names the better. Since we often spend most of our time reading other people's code, the easier it us to understand the faster you can get your focus off the syntax and onto the logic. These days with IntelliSense and the like, it's not really a burden to err on the side of clarity whenever possible.



回答9:

I agree with @Johnny Wey; name your variables - for the same reason you name them in any other code! Don't understand this predalection away from clarity just because of the "in-line" nature of the code. Readability is key - at a glance/w/out having to "hover" over stuff; otherwise, you might as well say no variable needs to be named appropriately. Maybe a little leeway if used with something "Enuerable", but still nice to see (again at a glance) what the heck the code is doing. If variable type inference is relying on some generic type passed into the class or something, c'mon, name it. Make all code read like a sentence; the computers are supposed to be adapting to us ("humanizing"), not the other way around where we start acting like computers and getting cryptic just because we can/feel smarter/more like tech geeks when we do (temptation is there, I kno!). It's easy to type a clear name and you still have all the Intellisense/sentence completion options you do in named methods. Plus, hovering in the case of lambdas doesn't always give you info on the var (frustrating during debug), so it's nice to see "clear/representative enough" naming, esp for new devs who havent been thru all the mental gymnastics to be able to infer the types by traversing the statement context (which also can be cryptic).



回答10:

Shortening is better if the purpose of the variable is clear. Lambdas call for a functional style of writing, hence you see a lot of chaining in one single line. Its cleaner to see when you keep them short.

Another case is when sometimes you need to declare a dummy variable which has no relevance/meaning in that scope. In such cases I use _ which makes it clear for me. This comes handy especially during method overloading, for eg,

public Foo Do()
{
    return Do(_ => true);
}

public Foo Do(Func<T, bool> pattern)
{
    return SomethingElse(pattern);
}


回答11:

Based on the answers above, I think there is general consensus that, if you can't tell from the context what you are dealing with, using a descriptive name is better. For example:

entities.Where(person => person.Age >= 21);

In cases where the context is obvious, however, a single-letter name may actually help readability, because it makes it easier to focus on the critical information. For example:

people.Where(p => p.Age >= 21); or people.Where(x => x.Age >= 21);

The question is, which is better, p or x?

  • In favor of p, it's a familiar pattern in SQL queries and provides a little extra reminder that you are talking about a Person.
  • In favor of x, if you rename Person to Customer, you don't have to worry about fixing all your lambda parameters. If you had used p, it would actually be a little confusing if your code became customers.Where(p => p.Age >= 21), whereas x is basically agnostic.

I've recent started using x, and so far, I haven't noticed any significant downside, but please comment if you disagree.