Hacker News new | ask | show | jobs
by wenc 2690 days ago
LINQ isn't really inefficient as such -- that's not really how I would put it. When used correctly, the performance is pretty good and it buys you elegance and a massive amount of expressive power with relatively little performance tradeoff. I use LINQ everywhere in my code and the maintainability gains are palpable.

It does have overhead, but it shouldn't be avoided for that reason unless you're really trying to squeeze performance gains out of your code. Eric Lippert, the designer of LINQ, has this to say [1].

[1] https://stackoverflow.com/questions/3769989/should-linq-be-a...

2 comments

Though my understanding is that if you do something like this:

var a = new double[10000];

var b = a.Select(x=>x*x).ToArray();

I'd expect LINQ to create a List or a similar structure when executing the select, then copy the output to the final array. If you were operating on two arrays directly, I would expect less memory allocations (unless these things get optimized away).

No. The Select-statement is not evaluated until necessary, i.e. until ToArray() is called.
While your comment is true, I'm not sure how it's relevant. `ToArray` is still operating on the `IEnumerable` produced by Select, which doesn't tell you that the Select is itself operating on an array.

The CLR does do some type checking to try to propagate the size if it can, but that's by no means guaranteed.

Edit: In skimming the source available on sourceof.net, it looks to me like the array doesn't actually get propagated far enough, so the construct in GP will in fact incur several unnecessary array copies.

I'm curious what you saw. My understanding was that it's mostly generators, i.e. it's done through yields, not extra allocated arrays.
It's `ToArray` itself that's the problem. Since it doesn't know how big the array will be in the first place, it has to allocate a small array, start iterating, copy everything into a bigger array each time it runs out of space, and finally allocate an array of exactly the right size and copy everything into that.

You can see the `ToArray` implementation at [0], which defers the implementation to [1]. The implementation checks for ICollection to get the exact size, but the type [2] that `Select` returns doesn't implement ICollection, so `ToArray` has to fall back to the less efficient algorithm.

[0] https://referencesource.microsoft.com/#System.Core/System/Li...

[1] https://referencesource.microsoft.com/#System.Core/System/Li...

[2] https://referencesource.microsoft.com/#System.Core/System/Li...

That's more or less what I had in mind without being certain of the details.

Was trying to open your links but I am served an expired tls certificate from Microsoft!

Ugh I made a mistake -- Eric Lippert isn't the designer of LINQ. That would be Erik Meijer [1].

[1] https://en.wikipedia.org/wiki/Erik_Meijer_(computer_scientis...