|
Having scored technical interview questions/tests before, I can tell you now, that developers that don't know-and-use linq, are the bottom of the barrel...
In one of the threads of this discussion performance is talked about, and while true that raw performance of a for/foreach for basic enumeration is marginally better, and has less overhead, you'll find that linq performs scores faster for more complex enumerations.
It basically comes down to devs not really understanding how they are putting code together, and linq is a great way to build up an enumerator before actually executing it. It is simply plain wrong to say linq doesn't perform as well, because not only did the succinct linq answers perform better than the code of the senior devs that were taking those tests, but we ran benchmarks, and the memory footprint was minimal in comparison, and every time a linq expression was used, the unit test covering the question passed, whereas it was closer to 20% for devs not writing linq (there was time pressure on the tests - I am sure the number would have crept up had there been more time, but it also shows that linq was faster to write a solution with).
Whether you think it is less readable, less simple or less maintainable is truly your opinion, but it sounds as though you, and others posting in this discussion, actually need to do some research on linq, because it shows a lack of understanding of the other benefits too.
Yes, it can be abused, but in the right hands it can produce some fantastic results.
|
|
|
|
|
I have to admit that I hate the more sql form of LINQ and find it extremely unreadable even though I am pretty comfortable with SQL. As far as debugging, I have to agree that it is much harder to debug, but it is also true that a long equation is harder to debug than breaking it up into pieces. I have had times in the past when I was having difficulty with a LINQ statement and did break it up, just like on an equation that was giving me problems. However, generally, I find that my LINQ statements are a lot more reliable than when I try to do the same thing without LINQ. I am of course talking about the simple case that you have. Personally I find the LINQ statement clearer then the foreach statement and the if statements. Also, I like to be able to see as much flow of the class and method as I can when looking at them on the screen, so I prefer much more compact code, but that is probably because I am more the type that wants to see the forest, and not focus on the trees. I can understand the complexity concern on more complex LINQ statements, but in order to reproduce the same thing, like the capability of joins, I would need a lot of code, and much easier to introduce errors.
In other words I like LINQ, and to me it is where programming languages are going. It provides an awful lot of power, and saves a lot of programming. If we took your approach to the extreme we would still be using assembly language. After all is in not easier to debug
b = 6
a = b / 2
c = b * a + 4
Would you also advocate getting rid of SQL. SQL is horrible to debug, and I think worse than using extension methods, but you are basically advocating the elimination of SQL. It is also extremely difficult to understand. I have worked with some SQL that goes on for pages, it was miserable.
|
|
|
|
|
Nope, I love that style of programming.
It's SO much more readable than a foreach/for/while loop.
It becomes immediately clear what the code does.
There's some collection than we need to filter, transform and process whereas a loop is just a loop and might do all those things, but you won't know until you read through the loop, probably with a lot more code to keep the new lists and counters. I've found a lot more unreadable loops than LINQ queries. I have no idea why you'd find it unreadable, it reads almost like natural language...
Anyway, that style is necessary for LINQ to SQL/Entities (because loops can't build expression trees, convert that to SQL and be lazy evaluated). And if I had to choose between LINQ or plain old SQL I'd choose LINQ wherever possible.
Only the .ForEach() is an odd one. It's defined on List<t> and not as a LINQ extension method because ForEach, by definition, has side-effects and LINQ was designed keeping the functional paradigm in mind. I never use it.
|
|
|
|
|
Sander Rossel wrote: I have no idea why you'd find it unreadable, it reads almost like natural language.. I think the problem is it's the wrong language for me. I don't think in terms of filters and transformations but this style forces me to.
|
|
|
|
|
I do think that way, but your style forces me not to. From now on I'll consider for loops a cancer
|
|
|
|
|
Sander Rossel wrote: It becomes immediately clear what the code does.
I think this is the important part. You focus on what the code does, without caring how this is done. As long as it does what it promises (which is the case with LINQ - usually) you're fine.
So you're abstracting away how you would (for example) filter the collection.
|
|
|
|
|
Yeah, and the how becomes so much more easier to read when you know what it is supposed to be doing in the first place
|
|
|
|
|
harold aptroot wrote: Is this style cancer?
No, next question.
harold aptroot wrote: why is this style popular?
Because it's superior to the other style. (I'm not talking about runtime performance here)
|
|
|
|
|
harold aptroot wrote: Is this style cancer? Absolutely!
A page full of IF...GOTO statements looks far more organised!
You don't even need ELSE s, or any of that indentation that makes the page a mess!
I wanna be a eunuchs developer! Pass me a bread knife!
|
|
|
|
|
When I started programming, "some" years ago, people where complaining about the performance of Object Oriented Programming (I won't speak of assembly vs. "high-level" language).
A "few" years later, when .NET arrived, the same was said regarding the use of the Framework compared to native code.
Nothing changes…
|
|
|
|
|
I didn't even mention performance, but sure, it aint great.
|
|
|
|
|
The "idea" isn't bad per say ... just that it tends to be taken too far.
Personally I try to keep such Linq chains down ... at most two dots in such a call (at least that being a quick-n-dirty rule-of-thumb). Especially as a normal for/foreach tends to be more efficient too, your sample is quite litterally performing 3 loops where one for loop would have sufficed.
The only time I feel such long chain of Linq extension methods make sense is if using the Linq SQL syntax instead. Though it's still not very efficient, actually less so than the pseudo FP style.
|
|
|
|
|
irneb wrote: your sample is quite litterally performing 3 loops where one for loop would have sufficed.
you should really take a look on what the compiler does when it enconters the yield keyword, you might be surprised to find out it's not as inefficient as you think.
|
|
|
|
|
Sentenryu wrote: you should really take a look on what the compiler does when it enconters the yield keyword
Not even slightly sure what you mean by that ???
Here's a test: BenchLinqLoops[^]
The chain of Linq statements clearly perform 3 loops (one of which is unnecessary). Yield doesn't "magically" fix that. And to show by how much such Linq chains (and even the Linq-to-SQL version) adds extra overhead - look at the performance of that yield function.
|
|
|
|
|
And just to make doubly sure no JIT optimizations skew the benchmark - I added an extra loop before starting the stopwatch, and rearranged the orders:
BenchLinqLoops[^]
Now you actually see the SQL variant's "extra" overhead - i.e. being translated into (effectively) the LinqAddXToEven2Loops function before it runs.
|
|
|
|
|
harold aptroot wrote: Is this style cancer?
No.
Linq has both it's Pro's and Con's. However, there is a clear benefit: Easy to write and easy to read (keep in mind that, if using Visual Studio, you have full intellisense support. And you can use your favourite code template, too.)
someStuff.Where(c => c != What).Select(d => d + The).Foreach(e => Hell(e));
looks better to me than
List<SomeStuff> tmpStuffList = new List<SomeStuff>();
for (int i = 0; i < someStuff.Count - 1; i++)
{
if (someStuff[i] != What)
{
tmpStuffList.Add(someStuff[i]);
}
}
for (int n = 0; n < tmpStuffList.Count - 1; n++)
{
Hell(tmpStuffList[n]);
}
I'll stick to the LinQ way of Querying.
|
|
|
|
|
Well, you did use some unnecessary stuff there.. temporary list isn't necessary, and those -1's should obviously not be there.
|
|
|
|
|
Sorting arrays in asp pages is ok I guess.
For business logic I would recommend an traditional approach.
so, yea, cancer for sure!
//ra
|
|
|
|
|
boss: "we need an else statement adding for when 'c' == Who and to run "Heaven(e)"
programmer: "right, that will be 2 hours."
foreach(var stuff in someStuff) {
if(stuff == What) {
Hell(stuff + The)
}
else if(stuff == Who) {
Heaven(stuff)
}
}
Boss: We all so need to call Devil() for when stuff it is "What".
|
|
|
|
|
harold aptroot wrote: Is this style cancer?
No.
harold aptroot wrote: Side question, why is this style popular?
It's part of the gradual shift from imperative programming to declarative programming. See also: javascript array functions.
|
|
|
|
|
We should be using that syntax because it's cleaner and more readable than lots of indented loops.
Our problems (at this point) are
- It's inefficient
- There's not enough good guidance on not doing dumb things (ToArray etc being case in point).
EF does a helluva job converting LINQ to SQL so what would be interesting is if there was a preprocesser that went through the whole LINQ chain, worked out what was really happening, then optimised (ie not did a bunch of stuff, parallelised other stuff, vectorised some stuff etc) and made it more efficient than foreach loops (which themselves are not efficient).
We shouldn't have a million devs optimising the same code. We should be able to express the code in elegant syntax and have the tools do the optimisation.
cheers
Chris Maunder
|
|
|
|
|
Plain-old-for definitely will work too, but this "one-liner" is specially intended for simple cases, where "for" is just too much!
Say, you need just checked checkboxes:
var chs = AllChBoxes.Where(box => box.IsCheched);
...and now look what you have to do with for:
var chs = new List<CheckBox>();
foreach(var ch in AllChBoxes)
if (ch.IsChecked) chs.Add(ch);
You write THREE lines (what is obviously more to read + more error prone) and achieved... even worse result, since IEnumerable in one-liner takes less memory (if needed at all).
So get your a$$ from the criocamera and study new way!
|
|
|
|
|
Here it's still obvious. It's the chaining where things start to get confusing.
Besides, I can't agree with your statement that you must create a list, after all you need those checkboxes in order to do something with them, you can most of the time just do that in the very same loop that checks them.
|
|
|
|
|
You said "for vs LINQ", I show you obvious case where you're not right. If you wanna just discuss how long LINQ can be - it's different question.
You don't understand word "materialized". If you use "for", you have to create physical list, where you keep your objects. In case of LINQ you have Enumerator, which will not take any object until you ask! It's important difference when you have billion objects, where half of 'em match your query. Enumerator just pass 'em one-by-one (keeping memory consumption low exactly for ONE ELEMENT), while your "for" takes all necessary memory at once.
|
|
|
|
|
Thornik wrote: You said "for vs LINQ", I did not, I showed an example of what I deem unreasonable. Using a single clause is still clear, if often unnecessary, though I like Max for example - there's a case where it really is simpler than an equivalent explicit loop.
Thornik wrote: You don't understand word "materialized". If you use "for", you have to create physical list, where you keep your objects. Oh you mean the source, sure. foreach it is then, problem solved.
|
|
|
|