News for hackers. Stuff that matters.
Re:LINQ Ruined My Favorite Interview Question by corresation on Thursday July 11, 2013 @11:27AM (#6026629)
but seriously, if you're writing c# and not using LINQ all the time

You don't sound arrogant, but rather sound naive. I agree that someone who recruits surely should have known about and have experienced LINQ significantly by now, but the notion that you should be using it "all the time" is absolute nonsense.

I avoid LINQ. I encourage others to avoid LINQ. It is almost always a sign of bad code.

LINQ is syntactical sugar over basic set operations. It is perfectly fine if you're doing naive activities, such as the example give -- a contrived example of brute forcing a problem, where two approaches of the same very basic need unsurprisingly yield the same complexity -- but it falls apart in real-world persistent code with considered algorithms and storage. In real long term code, it is usually the canary in the mineshaft telling you that the developers aren't using proper algorithms or storage.

In many large-scale projects it invariably turns into the performance nightmare that ends up causing whole rewrites.

Again, not because of LINQ itself, which of course can do basic operations like grouping and sorting as quickly as you could do "by hand", but that it makes it so easy to do those things that developers start to resort to that as a catch-all magical solution that is costless because how much could a line or two of code cost? -- a master List<stuff> that they just sort and group by and select from all over the code (O(n) * O(n) * O(n)...why not?). The end result is that the data structures and encapsulation that should have happened never did, so while it might seem more concise and obvious on a one-to-one comparison with a loop perspective, neither case should ever have happened.

LINQ is the gun by which a lot of terrible programmers are repeatedly shooting themselves in the foot with, all while gloating about their concise code.

Re:LINQ Ruined My Favorite Interview Question by Strilanc on Thursday July 11, 2013 @12:52PM (#6027270)
(Note: When I say LINQ I am referring to the functional style it encourages, not the query syntax. The query syntax is nice, but it's just a trivial syntactic transformation.)

Correct me if I'm wrong, but the world is moving towards functional programming (i.e. LINQ) not away from it. Personally, I find LINQ far, far easier to read, write, and analyze. (On the other hand, I understand the deferred semantics and watch for warning signs like enumerating a sequence more than once.)

Honestly, a C# company avoiding LINQ sounds to me like the canary in the mineshaft telling you the company has programmers falling behind the times and doing things the hard way.

Re:LINQ Ruined My Favorite Interview Question by moomin on Thursday July 11, 2013 @03:40PM (#6028624)
I'm definitely in agreement with the last point. However, I originally said that good C# code contains a lot of LINQ, not that C# code with a lot of LINQ is necessarily good. Deferred execution is something that confuses people, but frankly, it's a concept they need to learn. It's been in the language since yield return got added in 2.0.

LINQ's deferred execution was the right choice for performance, but it's the hardest one. You've got to know when to call .ToList(). I'm not denying that I've seen people evaluate the same expensive list 100 times, use a join when precomputing a Dictionary would have been much faster, close a connection before the result is actually evaluated. But I've never seen C++ programmers say you can make mistakes with pointers, so don't them.

Clojure's lazy sequences are guaraanteed to evaluate once, but that comes at the expense of storage. In particular, a query like the one in the original blog post will evaluate multiple intermediate lists that then need to be thrown away. And indeed, they've introduced reducers to address this, which behaves more like LINQ.

Re:LINQ Ruined My Favorite Interview Question by gngeal on Thursday July 11, 2013 @05:15PM (#6029275)
In particular, a query like the one in the original blog post will evaluate multiple intermediate lists that then need to be thrown away.

Why not fuse the operations, if the values are immutable?

Re:LINQ Ruined My Favorite Interview Question by moomin on Friday July 12, 2013 @01:37AM (#6031110)
Well, there's two ways to do that in Clojure: write your own list processing (usually regarded as bad style) or use reducers. Both are appropriate in specific instances, but the fact remains that the lazy seq code above is the idiomatic way of doing it in Clojure. So the _default_ way of doing it is slower than LINQ's default way of doing things.

It wouldn't be hard to make LINQ behave like Clojure, either.

Re:LINQ Ruined My Favorite Interview Question by tholmes on Thursday July 11, 2013 @04:47PM (#6029126)
Don't forget about Memoize(). Often it can be a better choice than ToList().
Re:LINQ Ruined My Favorite Interview Question by corresation on Thursday July 11, 2013 @01:02PM (#6027352)
I'm not sure what you're actually arguing for or against. There is nothing at all wrong with functional programming, and such had nothing whatsoever to do with my comment. That LINQ happens to use some functional techniques doesn't make my criticism a criticism of fP.
Re:LINQ Ruined My Favorite Interview Question by Strilanc on Thursday July 11, 2013 @01:32PM (#6027568)
Functional languages use the concepts you're criticizing even more extensively than LINQ does.
Re:LINQ Ruined My Favorite Interview Question by corresation on Thursday July 11, 2013 @02:18PM (#6027963)
What are the "concepts I'm criticizing"? I suspect that you have absolutely no idea what the context of my comment was, because your diversion on the topic of functional programming is just grossly out of place.

LINQ encourages the belief that set operations are free, such that you no longer have to concern yourself with concepts like memoization or appropriate structures. This has nothing to do with functional programming. Literally at all.

Re:LINQ Ruined My Favorite Interview Question by Strilanc on Thursday July 11, 2013 @02:56PM (#6028317)
You've actually been pretty vague about the concepts you're criticizing, except for "LINQ". Now I can see you were alluding to just the deferred execution part (the "lack of memoization").

Basically, you're saying it's too easy to accidentally perform a computation twice by iterating through a sequence twice. Recurse on that problem and you get an exponential blowup.

That is actually a problem mostly unique to LINQ and it is really important that a programmer understand the deferred semantics. Some tools, e.g. ReSharper, will detect multiple enumerations and warn you about it. Judicious use of ToArray/ToList solves most issues with defer-splosion.

Re:LINQ Ruined My Favorite Interview Question by corresation on Friday July 12, 2013 @09:36AM (#6032478)
I haven't been vague whatsoever.
Re:LINQ Ruined My Favorite Interview Question by Strilanc on Friday July 12, 2013 @12:06PM (#6033305)
In your first post, everything is "linq is bad" in generic terms except for these two bits:

> "it falls apart in real-world persistent code with considered algorithms and storage"

> "it makes it so easy to do [grouping / sorting / etc] that developers start to resort to that as a catch-all magical solution that is costless because how much could a line or two of code cost"

With hindsight I know your issue is with LINQ's deferred non-memoized execution. It's really easy to enumerate a sequence twice, but every place you do that might add a factor of 2 to the runtime and so there's a danger of exponential blowup that must be avoided. But that's not what I see when I read the above.

The above reads as complaints about easy composability and worries about code monkeys failing to consider what the code they're writing will do. Those are standard "functional / high-level programming is bad" complaints. With hindsight I know that's not what you meant, but that's what it reads like.

Re:LINQ Ruined My Favorite Interview Question by hvidgaard on Friday July 12, 2013 @03:40AM (#6031387)
I get what you're saying, I understand it, and I agree with the pitfalls. But I really really really don't agree that one should avoid LINQ. Sure if you don't understand how it works, and how it impact the performance, you should use it less. But don't try and drag the language down because you find it difficult. LINQ is easily one of the best things that have happened to a mainstream language in a long time, and if used right it produce highly maintainable code, that is very easy to read and understand. A lot of data manipulation really is done on sets, and LINQ makes it a breeze to do.
Re:LINQ Ruined My Favorite Interview Question by corresation on Friday July 12, 2013 @09:36AM (#6032474)
But don't try and drag the language down because you find it difficult.

Oh give me a break. My exact complaint about LINQ is the opposite -- that it makes expensive operations seem simple, which with all innovations in language means that mediocre programmers will start abusing it in all codebases.

LINQ has a place. To say that one should be using it "all the time", however, is exactly as I said -- a canary in a coal mine. The only time I've ever come across the extensive use of LINQ it has been in horrific code.

Re:LINQ Ruined My Favorite Interview Question by jmcqk6 on Friday July 12, 2013 @10:58AM (#6032927)
So I'm guess you haven't done any programming with the reactive extensions yet?
Re:LINQ Ruined My Favorite Interview Question by corresation on Friday July 12, 2013 @03:11PM (#6034502)
And why would you guess that? Because I don't consider LINQ of Rx observers being a magic cure-all?

In fact, LINQ on Rx is a symptom of the classic LINQ issue -- don't have subscriber or source filtering, or coherent, useful events -- simply broadcast everything and through the magic, free filtering of LINQ all is solved in the consumer.

Re:LINQ Ruined My Favorite Interview Question by prospero on Thursday July 11, 2013 @12:06PM (#6026926)
Wouldn't it be (O(n) + O(n) + ...) at the worst? And if it's on lazy sequences, which I thought it was, then composing a .Select and an .Aggregate should only involve a single pass through the sequence.
Re:LINQ Ruined My Favorite Interview Question by corresation on Thursday July 11, 2013 @12:15PM (#6026980)
I'm not talking about individual LINQ queries, which themselves can be perfectly fine: Microsoft is pretty smart, so if you're doing basic LINQ for objects grouping and sorting and selecting, they're going to use decent algorithms given the structures used. There is nothing surprising that the submitted usage shows very similar performance, as in the end both cases are doing essentially the same thing.

The problem is that it makes it so conveniently easy to do brute-force tactics that....oh the horrible things I've seen...code gets littered with LINQ doing naive queries repeatedly over massive sets of data. Of course you need good coders and good code audits, but LINQ, I think, gives a unsupported sense of comfort that one is making good code (where if people had to code these as loops, it would become very evident very early on that maybe they should rethink their approach).