|
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?
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 that
var 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!
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...
|
|
|
|
|
OriginalGriff wrote: Would you like to write and debug "Except" each time you need it? Actually yes, so I wouldn't end up in that situation of horribly nested function calls in your second code block.
|
|
|
|
|
Instead having loads of repeated code everywhere for no real benefit? are you trolling?
|
|
|
|
|
It's literally a single "if" that's added into a loop. That's not enough to refactor out of it, anything it can be replaced by is at least as complicated. Writing an "except" method is certainly more complicated, and calling it isn't any simpler than what it replaces.
|
|
|
|
|
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 read
someList.Where(condition).Select(fields).Distinct().OrderBy(field)
than the alternative
HashSet<Type> distinctSet = new HashSet<Type>();
foreach(var item in someList){
if(condition){
distinctSet.Add(item);
}
}
<sort the set in whatever way you do it manually>
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.
|
|
|
|
|
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
|
|
|
|
|
It was hard for me too, but once you understand how the context shifts it becomes way easier. LINQ queries have a different flow from the rest of the imperative code and are best left a little separated from stuff like for loops and complex conditionals, they require you to use the same way of thinking you use when writing SQL. It's not that you are telling the machine what to do, you're telling it what you want done, so you read this:
someList.Where(condition).Select(field)
As "Give me field for all objects where condition is true" instead of "For each object, if condition is true, stuff field on another list".
Truth is, those kind of LINQ queries are just convenience. The real power of LINQ comes when you start using joins and groups, like this example from LINQPad (still on the simple side):
var query =
from o in Orders
group o by o.ShipCountry into countryGroups
select new
{
Country = countryGroups.Key,
Cities =
from cg in countryGroups
group cg.ShipPostalCode by cg.ShipCity into cityGroups
select new
{
City = cityGroups.Key,
PostCodes = cityGroups.Distinct()
}
};
that produces this output:
As much as I can write that using for loops and conditionas, i don't want to write it that way. Also, join's and group's are the only thing I'll ever use query syntax for, they are somewhat easier to understand that way.
|
|
|
|
|
Harold, is it easier on separate lines, or do you still find that difficult to read? (by the way, this is called "fluent syntax". I find when it's all on one line (except maybe calling .Single() or .First() or .ToList() at the end of something) it can be very difficult to read. But this I love:
someStuff.Where(c => c != What)
.Select(d => d + The)
.Foreach(e => Hell(e));
|
|
|
|
|
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.
|
|
|
|
|
Sentenryu wrote: calling a style "cancer" just because you don't want to learn how to read and use it
OP reminds me of this[^]
|
|
|
|
|
Linq is all about defining the query instead of the execution of the query. You say you can implement Except in a single line of code. Can you also do that for grouping, ordering, projection? And all those other possibilities, all used in combination?
Using Ling you are sacrificing a little performance, and you are (read: should be) gaining a lot in maintenance. You can implement the above probably without problems. Can you also read the implementation of others without any problems? Using Linq you and your co-workers are all using the same methods, and therefor, can read each others code a lot easier, compared to a different implementation for you and every co-worker you have.
Of course, you can completely kill the performance, and no-one will say that Linq is faster, and yes, you have to know what you are doing. But that is no different from all the 'other tools in your toolbox'.
|
|
|
|
|
Linq => Backward SQL
We're philosophical about power outages here. A.C. come, A.C. go.
|
|
|
|
|
Actually, I think of it as SQL the right way round.
A good clue comes from intellisense. It cannot get the field names unless you write the FROM before the SELECT.
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
Alan Kay.
|
|
|
|
|
I use whatever is appropriate, and refuse to use new language features just because they're new. I still resist using Entity Framework because generalization on that scale usually means bloated and inefficient code.
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
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?
|
|
|
|
|
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
|
|
|
|
|
BillWoodruff wrote: and will fail on an IEnumerable<WhatEver>
Which is why I have an extension method to overcome that shortcoming.
Marc
|
|
|
|
|
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<t> 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<T>(this IEnumerable<T> sequence, Action<T> action)
{
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
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
|
|
|
|
|
BillWoodruff wrote: I get a glimpse of your shadow going around a corner
You are generous as always!
There are some corners I probably should not be followed:
public static bool If(this bool b, Action action)
public static void IfElse(this bool b, Action ifTrue, Action ifFalse)
etc.
Let's just call those "experiments."
Marc
|
|
|
|
|
Ha! But then there is value in experiments:
public static void ForEach<T>(this IEnumerable<T> sequence, Action<T, int> action)
{
var index = 0;
foreach(T item in sequence) {
action(item, index);
index++;
}
}
For example, I am curious if I could find value in (probably with a different body implementation):
public static async Task ForEachAsync<T>(this IEnumerable<T> sequence, Func<T, Task> actionAsync)
{
foreach(T item in sequence) await actionAsync(item);
}
|
|
|
|
|
Is that a Smalltalk influence I detect?
In Smalltalk, there are no control flow statements beyond sending messages. However, the boolean object responds to the messages ifTrue: and ifTrue:Else:
(x < 3) ifTrue: [ x <- 3 ].
(x < 3) ifTrue: [ x <- 3 ] Else: [ x <- x + 1 ].
And of course similar constructs such as:
(x > 0) whileTrue: [ x <- x - 1 ].
Here [] denotes a block of code (similar to a closure) and <- denotes assignment.
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
Alan Kay.
|
|
|
|
|
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.
|
|
|
|
|
The newest thing? It has been around for almost 10 years...
The paradigm itself, readable, no side-effects code making heavy use of lambda's (or anonymous function) has been around almost as long as programming. It's called functional programming.
|
|
|
|
|