Using IEnumerable nonsense for everything
-
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?
Well, no, Harold, I haven't seen that style because I haven't read any buggy code that was written by someone who did not know that the 'ForEach sequence iterator only works on a List<T>, and will fail on an IEnumerable<WhatEver> ... until ... now :) Eric Lippert would agree with you, however, that the 'ForEach iterator is 'gang aft agley': [^]. As Eric (famously) said: "Remember, the purpose of code is not just to communicate to the compiler it is to communicate to the future reader of the code; make it as clear as possible." While I do think there's something that many programmers innately find "satisfying" psychologically about method chaining a la functional programming, perhaps there is also an attraction to writing the most recent syntax as a way to ... "be cool" ? But, wait a minute, what about when the purpose of the 'ForEach iterator is to operate on a "projected" IEnumerable to modify elements of a collection where attempting to modify those elements in standard 'for, 'foreach, loops would result in an error. In that case, perhaps the creation of an "extra" List in order to use 'ForEach is ... useful ? cheers, Bill
«There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008
-
Well, no, Harold, I haven't seen that style because I haven't read any buggy code that was written by someone who did not know that the 'ForEach sequence iterator only works on a List<T>, and will fail on an IEnumerable<WhatEver> ... until ... now :) Eric Lippert would agree with you, however, that the 'ForEach iterator is 'gang aft agley': [^]. As Eric (famously) said: "Remember, the purpose of code is not just to communicate to the compiler it is to communicate to the future reader of the code; make it as clear as possible." While I do think there's something that many programmers innately find "satisfying" psychologically about method chaining a la functional programming, perhaps there is also an attraction to writing the most recent syntax as a way to ... "be cool" ? But, wait a minute, what about when the purpose of the 'ForEach iterator is to operate on a "projected" IEnumerable to modify elements of a collection where attempting to modify those elements in standard 'for, 'foreach, loops would result in an error. In that case, perhaps the creation of an "extra" List in order to use 'ForEach is ... useful ? cheers, Bill
«There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008
BillWoodruff wrote:
Well, no, Harold, I haven't seen that style because I haven't read any buggy code that was written by someone who did not know that the 'ForEach sequence iterator only works on a List<T>, and will fail on an IEnumerable<WhatEver> ... until ... now
Damn :) Can I get away with this if I pretend it's my own extension method?
-
BillWoodruff wrote:
Well, no, Harold, I haven't seen that style because I haven't read any buggy code that was written by someone who did not know that the 'ForEach sequence iterator only works on a List<T>, and will fail on an IEnumerable<WhatEver> ... until ... now
Damn :) Can I get away with this if I pretend it's my own extension method?
Hi, Harold, I am sending you via mental telepathy one of my rationalization-rations; I don't know why the gods give me so many ... is it because it's so clear I need them ? cheers, Bill
«There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008
-
But surely you need to debug this as well? Just in case? And that would be harder than if it were a normal loop
Yes - but you need to debug the criteria it's using rather than the complete code - which isn't complicated. Would you like to write and debug "Except" each time you need it? :laugh: No - so you'd write it once and call it from multiple places. Which is exactly what I do when I use
aCollection.Except(anotherCollection)
- except I don't have to write it in the first place! And you have to admit thatvar inDuration = DiskFile.GetAll().Where(df => !df.HasDuration).Select(df => df.Video).Distinct();
Is a lot more readable than the "home brew" version using methods:
var inDuration = Distinct(Select(Where(DiskFile.GetAll(), Video), HasDuration));
Where it's a PITA to just make sure the brackets match up! :laugh: Yes, Linq methods can be slower to execute - but sometimes the absolute speed isn't that important, but reliability and ease of maintenance is.
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
-
Yes - but you need to debug the criteria it's using rather than the complete code - which isn't complicated. Would you like to write and debug "Except" each time you need it? :laugh: No - so you'd write it once and call it from multiple places. Which is exactly what I do when I use
aCollection.Except(anotherCollection)
- except I don't have to write it in the first place! And you have to admit thatvar inDuration = DiskFile.GetAll().Where(df => !df.HasDuration).Select(df => df.Video).Distinct();
Is a lot more readable than the "home brew" version using methods:
var inDuration = Distinct(Select(Where(DiskFile.GetAll(), Video), HasDuration));
Where it's a PITA to just make sure the brackets match up! :laugh: Yes, Linq methods can be slower to execute - but sometimes the absolute speed isn't that important, but reliability and ease of maintenance is.
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
-
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.PIEBALDconsult wrote:
What really irks me is the near-constant use of
ToList
orToArray
; those are definitely cries for help.Depends, if you are getting it off EF or OData, sometimes you want to do in-memory processing. Specially within services.
Regards, Nish
Website: www.voidnish.com Blog: voidnish.wordpress.com
-
PIEBALDconsult wrote:
What really irks me is the near-constant use of
ToList
orToArray
; those are definitely cries for help.Depends, if you are getting it off EF or OData, sometimes you want to do in-memory processing. Specially within services.
Regards, Nish
Website: www.voidnish.com Blog: voidnish.wordpress.com
Uh huh, so why can't you?
-
Uh huh, so why can't you?
Uhm, I thought you said any use of ToArray is a cry for help?
Regards, Nish
Website: www.voidnish.com Blog: voidnish.wordpress.com
-
Uhm, I thought you said any use of ToArray is a cry for help?
Regards, Nish
Website: www.voidnish.com Blog: voidnish.wordpress.com
"the near-constant use"
-
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?
Definitely, cancer in my world. My goal is to build quality software that any level of developer can easily understand and change, if needed. Hey, I might die tomorrow. I don't run after the newest thing and don't try to be fancy or cute. It is probably popular because organizations, such as MSFT, bring out new features to get more people on board using their products. Young people just starting out have a difficult time getting established, plus they like to be fashionable; so they try to code fancy with all the new stuff, to make the big money.
-
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?
It seems I may be in the minority, but I don't find that (or predicates in general) unreadable. /ravi
My new year resolution: 2048 x 1536 Home | Articles | My .NET bits | Freeware ravib(at)ravib(dot)com
-
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?
As others have said, it might give you "nerd points", but IMO it is the C# equivalent of APL one-liners - easy to write, impossible to debug or understand 6 months down the line. Under some circumstances, this coding style may produce faster code, but that remains to be measured.
If you have an important point to make, don't try to be subtle or clever. Use a pile driver. Hit the point once. Then come back and hit it again. Then hit it a third time - a tremendous whack. --Winston Churchill
-
Well, no, Harold, I haven't seen that style because I haven't read any buggy code that was written by someone who did not know that the 'ForEach sequence iterator only works on a List<T>, and will fail on an IEnumerable<WhatEver> ... until ... now :) Eric Lippert would agree with you, however, that the 'ForEach iterator is 'gang aft agley': [^]. As Eric (famously) said: "Remember, the purpose of code is not just to communicate to the compiler it is to communicate to the future reader of the code; make it as clear as possible." While I do think there's something that many programmers innately find "satisfying" psychologically about method chaining a la functional programming, perhaps there is also an attraction to writing the most recent syntax as a way to ... "be cool" ? But, wait a minute, what about when the purpose of the 'ForEach iterator is to operate on a "projected" IEnumerable to modify elements of a collection where attempting to modify those elements in standard 'for, 'foreach, loops would result in an error. In that case, perhaps the creation of an "extra" List in order to use 'ForEach is ... useful ? cheers, Bill
«There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008
BillWoodruff wrote:
and will fail on an IEnumerable<WhatEver>
Which is why I have an extension method to overcome that shortcoming. ;) Marc
Imperative to Functional Programming Succinctly Contributors Wanted for Higher Order Programming Project! Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny
-
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?
harold aptroot wrote:
Is this style cancer?
Not in my opinion. So what you'd have is (a bit cleaned up and assumptions made):
foreach(var stuff in someStuff)
{
if (stuff.c != "What")
{
Hell(stuff.d + "The");
}
}harold aptroot wrote:
Side question, why is this style popular?
I think, given the above example, the answer to that is obvious. But if you want it enumerated (hardeeharhar): 1) Easier to understand the logic 2) Simpler code
harold aptroot wrote:
I file this firmly under "stupid one-liner 'clever' code with no benefits to compensate".
Sure, it can be abused, but for me, the Linq statement is so much more readable and understandable, in a very short order of time, than the longer format. Consider also some order advantages:
someStuff.Where(c => c != What).Select(d => d + The).OrderByDescending(q => q.CreateDate).Foreach(e => Hell(e));
What a PITA to have to create yet another list to reverse the order, and if you're abstaining from Linq altogether, you'd probably have to call a method to re-order the list on the desired field. More kruft, more complexity, more things to go wrong, more hard to understand imperative code. Furthermore, if you need to change the order, the above "long" code example breaks, because now you have to create a separate list of the filtered items so you can then sort that -- I assume you wouldn't want to sort the unfiltered list! So, add another item to the reason the "style cancer" is better: 3) more maintainable The style cancer, as you call it, is very much like functional programming, where each function results in an output that you pipe to the next function as its input. It's a much much cleaner style. Marc
Imperative to Functional Programming Succinctly Contributors Wanted for Higher Order Programming Project! Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny
-
Another issue is trying to debug it. If you get an error or exception then it's harder to debug when it's effectively a single statement.
harold aptroot wrote:
Side question, why is this style popular?
I worked with someone that used linq wherever possible. His argument was that it was "faster". I think people think that because something is new it's fast *shrug*
I put each method call on a separate line for this very reason. e.g.
someStuff
.Where(c => c != What)
.Select(d => d + The)
.Foreach(e => Hell(e));What do you get when you cross a joke with a rhetorical question? The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism. Do questions with multiple question marks annoy you???
-
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 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.
-
Another issue is trying to debug it. If you get an error or exception then it's harder to debug when it's effectively a single statement.
harold aptroot wrote:
Side question, why is this style popular?
I worked with someone that used linq wherever possible. His argument was that it was "faster". I think people think that because something is new it's fast *shrug*
He could have meant it was faster to write than do the foreach and the if statements. Not that it runs faster. And I find it is much faster to write.
-
BillWoodruff wrote:
and will fail on an IEnumerable<WhatEver>
Which is why I have an extension method to overcome that shortcoming. ;) Marc
Imperative to Functional Programming Succinctly Contributors Wanted for Higher Order Programming Project! Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny
Marc Clifton wrote:
Which is why I have an extension method to overcome that shortcoming
You and Eric: Eric Lippert, 2009, op. cit. "A number of people have asked me why there is no Microsoft-provided “ForEach” sequence operator extension method. The List class has such a method already of course, but there’s no reason why such a method could not be created as an extension method for all sequences. It’s practically a one-liner:"
public static void ForEach(this IEnumerable sequence, Action action)
{
// argument null checking omitted
foreach(T item in sequence) action(item);
}For me, seems like something happened this year where suddenly I felt more comfortable (secure ?) using Linq goodness, and Yield Return, and IEnumerables of whatever, and writing extension methods that have a "socket" for an Action, or Func. I have seen some students bounce off those semantics/facilities, and some take to it like the proverbial "ducks to water." And (I hope you can still blush), you were an influence on me to "get more into" the method-chaining style, which I really like, now. Not that I am "catching up" with you (technically) in any way, though: occasionally I get a glimpse of your shadow going around a corner :omg: thanks for the mentories, Bill
«There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008
-
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?
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 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.
Read my (free) ebook Object-Oriented Programming in C# Succinctly. Visit my blog at Sander's bits - Writing the code you need. Or read my articles here on CodeProject.
Simplicity is prerequisite for reliability. — Edsger W. Dijkstra
Regards, Sander
-
harold aptroot wrote:
Is this style cancer?
Not in my opinion. So what you'd have is (a bit cleaned up and assumptions made):
foreach(var stuff in someStuff)
{
if (stuff.c != "What")
{
Hell(stuff.d + "The");
}
}harold aptroot wrote:
Side question, why is this style popular?
I think, given the above example, the answer to that is obvious. But if you want it enumerated (hardeeharhar): 1) Easier to understand the logic 2) Simpler code
harold aptroot wrote:
I file this firmly under "stupid one-liner 'clever' code with no benefits to compensate".
Sure, it can be abused, but for me, the Linq statement is so much more readable and understandable, in a very short order of time, than the longer format. Consider also some order advantages:
someStuff.Where(c => c != What).Select(d => d + The).OrderByDescending(q => q.CreateDate).Foreach(e => Hell(e));
What a PITA to have to create yet another list to reverse the order, and if you're abstaining from Linq altogether, you'd probably have to call a method to re-order the list on the desired field. More kruft, more complexity, more things to go wrong, more hard to understand imperative code. Furthermore, if you need to change the order, the above "long" code example breaks, because now you have to create a separate list of the filtered items so you can then sort that -- I assume you wouldn't want to sort the unfiltered list! So, add another item to the reason the "style cancer" is better: 3) more maintainable The style cancer, as you call it, is very much like functional programming, where each function results in an output that you pipe to the next function as its input. It's a much much cleaner style. Marc
Imperative to Functional Programming Succinctly Contributors Wanted for Higher Order Programming Project! Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny
Exactly, well put :thumbsup:
Read my (free) ebook Object-Oriented Programming in C# Succinctly. Visit my blog at Sander's bits - Writing the code you need. Or read my articles here on CodeProject.
Simplicity is prerequisite for reliability. — Edsger W. Dijkstra
Regards, Sander