Using IEnumerable nonsense for everything
-
You shown long LINQ query and start talking about "foreach". But even being that long, FORMATTING RULES. :)
someStuff.Where(c => c != What) // comment why you do it
.Select(d => d + The) // comment why you do it
.Foreach(e => Hell(e));// comment why you do it> Oh you mean the source, sure. foreach it is then, problem solved. Nope. You do not solve problem if you prepare list of objects thru foreach - you have to put 'em in a List<> (because hell knows how it will be used later). In case of LINQ you prepare just REQUEST (which takes zero memory), which later will enumerate any amount of objects. And BTW same request can be enumerated many times.
-
No, he meant to execute. I set up some experimental code that looped many times using the various methods like native code and linq and timed them. I also pointed out that the linq code was using anonymous methods and that they had overhead too.
Well I do find it a lot faster to write. I would expect it to have poorer performance, but don't know how bad. I believe is that if you have performance issues, find out the methods that use the most resources, and optimize them. This is where get most bang for the buck.
-
harold aptroot wrote:
Is this style cancer?
Yes. Many fans of that style don't realize how many times the data gets copied and iterated when they do nonsense like that. What really irks me is the near-constant use of
ToList
orToArray
; those are definitely cries for help. Even a simpleforeach
should generally be avoided in situations where afor
will perform at least as well.I would argue the total opposite. This is not cancer. The data does not get copied and iterated because this is all lazy processed. Perhaps you dont understand how these methods actually work. Do you know how many times it took me hours to construct a proper nested for loop? With this style the complex can be accomplished in minutes. You need to call ToList when you are complete to finally iterate over the entire IEnumerable. Because the Where and Select methods are lazy processed I have found that you dont get the proper results at the end unless you call ToList. Also calling ToList is needed when performing async or multi threaded code. You need your own copy of the items to mess with otherwise you will get errors. As for performance we are talking small milliseconds longer. I can read and understand that one liner perfectly in 5 seconds. Can you honestly say that a for loop is perfectly understandable in that amount of time? I think not. Also did you know you can iterate over thousands of records in the same amount of time it takes to do an if(x == y) statement. "if" comparisons are the slowest code to run.
-
Richard Deeming wrote:
Writing all of your code in one big
Main
function is faster than any of this "object-oriented" nonsense.That is, almost certainly, not true. With one big function, the optimizer will have to practically shut-down. Many smaller functions can be highly optimized.
Richard Deeming wrote:
And using C or assembly will be much faster than this JIT-compiled C# nonsense.
Again, real world examples have shown that letting the computer do things like managing your resources, is much faster than trying to do it yourself manually.
Truth, James
I would be a bit surprised if your first point was true. Please give me a couple examples of optimizations that depend on function size.
-
I would be a bit surprised if your first point was true. Please give me a couple examples of optimizations that depend on function size.
Optimization largely depends on tracking the lifetime of variables:
for(int i =0; i< 100; ++i)
{...}will be better optimized, than this...
int i;
for(i =0; i< 100; ++i)
{...}just because the compiler knows that "i" is never used again outside that for loop. In the latter, space must be allocated for i on the stack, and it must be stored there. In the first, "i" may live at it's entire existence in a register. Now, in an example as small as the above, a good compiler may still realize that even the second "i" is not used again, but the larger that function gets, with more things to track, the optimizer begin to give up.
Truth, James
-
Optimization largely depends on tracking the lifetime of variables:
for(int i =0; i< 100; ++i)
{...}will be better optimized, than this...
int i;
for(i =0; i< 100; ++i)
{...}just because the compiler knows that "i" is never used again outside that for loop. In the latter, space must be allocated for i on the stack, and it must be stored there. In the first, "i" may live at it's entire existence in a register. Now, in an example as small as the above, a good compiler may still realize that even the second "i" is not used again, but the larger that function gets, with more things to track, the optimizer begin to give up.
Truth, James
That might be true but it comes at the cost of jumps and stack management for function calls. I think you will be hard-pressed to find an example of one block of code that runs slower than similar code split into more functions.
-
For debugging, though, if you convert the lambda expression into a lambda statement, you can put a breakpoint in it. That can help in debugging. Usually what I end up doing is split the fluent chain into separate pieces if I need to debug it. That being said, this is usually a style I employ as I'm finishing up code and have already tested it while doing my normal refactoring. (and when I know high performance is not necessary)
I just set breakpoints on the lambda expressions in the statements. The debugger is a little finicky on setting them there -- you have to click somewhere in the RHS of the lambda and then hit F9 to set the breakpoint. No harder to debug than any other bit of code. I use Linq a lot, but for non-performant areas. I don't expect it to be faster to run, only faster to write, debug and maintain.
We can program with only 1's, but if all you've got are zeros, you've got nothing.
-
I would argue the total opposite. This is not cancer. The data does not get copied and iterated because this is all lazy processed. Perhaps you dont understand how these methods actually work. Do you know how many times it took me hours to construct a proper nested for loop? With this style the complex can be accomplished in minutes. You need to call ToList when you are complete to finally iterate over the entire IEnumerable. Because the Where and Select methods are lazy processed I have found that you dont get the proper results at the end unless you call ToList. Also calling ToList is needed when performing async or multi threaded code. You need your own copy of the items to mess with otherwise you will get errors. As for performance we are talking small milliseconds longer. I can read and understand that one liner perfectly in 5 seconds. Can you honestly say that a for loop is perfectly understandable in that amount of time? I think not. Also did you know you can iterate over thousands of records in the same amount of time it takes to do an if(x == y) statement. "if" comparisons are the slowest code to run.
-
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.
-
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.
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.
-
I promise you I'm not just flaming, I just really find those chained LINQy things hard to read. It's not like I haven't tried, I've been reading them for nearly a decade, I'm not getting used to them. It takes an extra step in my mind somehow, normal code I read and build up a picture of it in my mind, LINQy stuff I read, tear down, then build a picture. Clearly that is not the case for everyone here
I can certainly understand, especially when you are dealing with SelectMany, or Join. Those can get nasty, but then the code to do them would be nasty anyway. so I do not see a good reason to code it with foreach and if statements.
-
this thread only shows that you're hellbent on your "One true way" of coding, so there's not much to discuss here. but do keep in mind that calling a style "cancer" just because you don't want to learn how to read and use it is exactly what causes so many flamewars on the IT world (tabs vs spaces anyone?). Sure, you tell me it's just an
if
but you know what? I much prefer to readsomeList.Where(condition).Select(fields).Distinct().OrderBy(field)
than the alternative
HashSet distinctSet = new HashSet();
foreach(var item in someList){
if(condition){
distinctSet.Add(item);
}
}specially if you want to roll your own sorting method at the end. As a last note, i sometimes work with code where the order of operations (where, distinct, etc) sometimes yields different results and is important (due to crazy business rules, what can you do), so it's way easier to get the intent from the link way, but I recognize that you mileage may vary on that last one.
Sentenryu wrote:
calling a style "cancer" just because you don't want to learn how to read and use it
GeoGame for Windows Phone | The Lounge Explained In 5 Minutes
-
PIEBALDconsult wrote:
Many fans of that style don't realize how many times the data gets copied and iterated when they do nonsense like that.
Many fans do realize, we just don't care :) Would I use the style for loops that should be executed milion times a second, like image processing? No. Would I use it for everything else? Hell yes.
GeoGame for Windows Phone | The Lounge Explained In 5 Minutes
-
Why? A for loop tends to be far clearer and easier to read, not to mention faster and more efficient.
obermd wrote:
A for loop tends to be far clearer and easier to read
Because that's your opinion and when I code I don't take your opinions into account :)
GeoGame for Windows Phone | The Lounge Explained In 5 Minutes
-
You've probably seen this style if you're done anything with C# after 2007 or so. someStuff.Where(c => c != What).Select(d => d + The).Foreach(e => Hell(e)); Instead of, you know, a plain old `for` loop with an `if` in it and so on. Or maybe `foreach` if you want to be fancy. So, now we have nearly a decade of experience with this, can we finally settle this question: Is this style cancer? I still think it is, and the retort "you just have to get used to it" isn't going to work any more. I file this firmly under "stupid one-liner 'clever' code with no benefits to compensate". Yes, I've argued in the past that "clever code" isn't necessarily bad, and I'll keep saying that - there's a time and a place for it. But not if you're just trying to be cute. "Oh look at me, I put everything on one line, +1 nerd points for me" And this is even worse. It's not just cute with no benefits to compensate, it's cute and harder to read. Side question, why is this style popular?
I agree with Harry here, but I think a lot of developers, including maybe even Harry, are missing the point. Programming code is not there to suit the computer, or the compiler, or the run-time engine. If it was, we would do everything in machine code, or p-code, or whatever. Code is there to be read by PEOPLE. Anything that obscures that intent is, basically, just pretentious BS. Why should I have to stop and ponder your code for even 3 seconds? Every time I see that line?
-
Marc Clifton wrote:
readability, simplicity, maintainability,
These might have sold it to me if they were true. They're true for you, but not for me. The functional syntax I see as detrimental.
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.
-
F-ES Sitecore wrote:
That line throws a null exception...can you look at the line that threw the exception and know what the issue is?
Assuming I'm using LINQ, the most likely culprit would be
GetAList
returningnull
. Failing that, I'd have a stack-trace to tell me where the exception occurred. :)
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
But you agree it wouldn't be immediately obvious like it would if you weren't using linq?
-
I would be a bit surprised if your first point was true. Please give me a couple examples of optimizations that depend on function size.
Mike Marynowski wrote:
I would be a bit surprised if your first point was true. Please give me a couple examples of optimizations that depend on function size.
Small functions can be in-lined by the optimiser, so this code
foreach(string x in y)
{
x = x.Trim().ToLower();
DoSomething (x);
}function DoSomething(string s)
{
if (s.StartsWith("hello"))
{
s = "test";
}
}might be optimised to this
foreach(string x in y)
{
x = x.Trim().ToLower();
if (x.StartsWith("hello"))
{
x = "test";
}
}thus avoiding a code jump\stack update etc.
-
Mike Marynowski wrote:
I would be a bit surprised if your first point was true. Please give me a couple examples of optimizations that depend on function size.
Small functions can be in-lined by the optimiser, so this code
foreach(string x in y)
{
x = x.Trim().ToLower();
DoSomething (x);
}function DoSomething(string s)
{
if (s.StartsWith("hello"))
{
s = "test";
}
}might be optimised to this
foreach(string x in y)
{
x = x.Trim().ToLower();
if (x.StartsWith("hello"))
{
x = "test";
}
}thus avoiding a code jump\stack update etc.
Yes, but that optimization doesn't have to be made if you are putting everything into a big block of code lol. I'm not advocating for that approach, just saying that splitting into functions is unlikely to boost performance...in the best case it will match performance after optimizations, which is basically what is happening in this example.
-
But you agree it wouldn't be immediately obvious like it would if you weren't using linq?
If I wasn't using LINQ, then I'd be able to identify which line in the massive complicated method the exception was thrown from. Whether it would be obvious why the exception was thrown is a different matter. :)
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer