Even if it is being written and currently maintained by one of our sharper folks, people move on or change roles, and projects shift to other staff for long term maintenance. Who's going to be maintaining this project in 2-4 years? This project needs to be written with them in mind.
List<AClass> original; // perhaps as a parameter to the function
List<AClass> filtered = original.Where(x => x.Field > 10);
Arguing that I should instead have just used for loops (showed him foreach and he agreed that that was better, at least) like: List<AClass> filtered = new List<AClass>();
foreach(x in original)
if(x.Field > 10) filtered.Add(x);
Ok, so it's only two lines longer (three if you split the if and its effect, 5 if you also add in braces, 7 if you put opening braces on their own lines). The `Where` version is not that complicated, and only requires understanding one (potentially) new concept for programmers, namely anonymous functions.Wouldn't the briefer, but still clear, code be preferable for maintenance?
The "rule" I apply is "code should be written primarily for people to read and only incidentally for machines to execute" which, although very subjective, provides a good foundation for everyone to start from.
Because at some point that programmer learned how a for loop works. Programmers are smart people; they should learn how flatMap or any other abstraction works. Abstractions are the tools of the trade. Imagine a mechanic that didn't use power tools because he/she didn't understand them.
Your logic about an abstraction being "legitimately obfuscated" "until you grok" it could apply to nearly every advancement in programming, and needs to be qualified with some notion of why you've decided to apply it to the layer of abstraction that you have.
If the final order of the output is important (and it frequently is), you have to understand not only "map, then flatten", but the order in which the flatten occurs. And that appears to be implementation dependent.
List(List(1,2), List(3,4), List(5,6)).flatten -> List(1, 2, 3, 4, 5, 6)
Set(Set(1,2), Set(3,4), Set(5,6)).flatten -> Set(5, 1, 6, 2, 3, 4)http://reactivex.io/documentation/operators/flatmap.html
Granted, this refers to a higher level abstraction on a sequence of realtime events, but as we delve more into green threads and lazy evaluation, these kinds of solutions will become more common.
I really don't believe that there is no obvious way to guarantee the ordering of a given flatten command without looking into its implementation. Of course, I'm admittedly partial to Python's solution - use an explicit list comprehension:
>>> g = lambda i: (i, -i)
>>> [x for y in [1, 2, 3] for x in g(y)]
[1, -1, 2, -2, 3, -3] var foo = things.SelectMany(thing=>thing.SubThings).OrderBy(subthing=>subthing.PropertyICareAbout)
Particularly if things is some interface that I don't know the details of, like IEnumerable, ICollection or IDictionary.And dear heavens, achieving more with less code is the last thing any respectable developer would want.
The problem is, clarity for who? For the developer? For another, equally skilled developer? Or for the developer's less skilled coworkers? For the least skillful coworker? To whom does the code need to be clear?
If you have a coworker who doesn't understand it, pair them with someone more senior until they get up to speed. If they are simply cognitively incapable of understanding the concept of mapping a function, in my opinion they are not capable of becoming a good developer.
Yes, there are times when reducing lines of code reduces clarity. But in my experience they are rare and exceptional. Far more real world code lacks clarity due to verbosity than from being overly terse.
Sure, they could be taught. But they're busy being taught other things - Android, say, or the latest JS framework. So there's an opportunity cost to teaching them - it takes away time and attention from teaching them other things, things that may move us closer to our business goals. So in practice, yes we can teach them, and no we won't.
And now that one line of code can decrease clarity for the team.
In my opinion and experience, Resharper is the easiest way to learn LINQ, before you even start looking at all the other dumb, inconsistent and error-prone stuff that people will do because it compiles, blissfully unaware of all the foot-guns it contains.
The solution is to simply drop the use of flatmap (or any other function which eliminates loops). In my experience, that level of abstraction is the kind of thing which confuse new developers who have not (yet) been exposed to the terminology introduced by functional programming. It comes across as "clever" and "obfuscated". And it really is quite clever - you turn a 4 line for loop with accumulators into a single line of code. But it's also legitimately obfuscated as well, until you grok how flatmap works.
Ultimately, a for loop can be understood by almost any programmer you will encounter. There's more code, it does the exact same thing as a flatmap, but (as the OP points out) the function is still pure.