Mostly unrelated - but this reminds me of a project I did years ago to put an entire raytracer in a single C# LINQ expression.
https://github.com/lukehoban/LINQ-raytracer/blob/master/READ...
Mostly unrelated - but this reminds me of a project I did years ago to put an entire raytracer in a single C# LINQ expression.
https://github.com/lukehoban/LINQ-raytracer/blob/master/READ...
I have been warned that LINQ is often inefficient compared to raw C# with the same functionality -- but I have my doubts as the MS C#/.net put quite a lot into LINQ efficiency under the hood. Did you test this against any raytracing setups that don't use LINQ?
But the worst performance hits in Linq come when people don’t know how to use it. The biggest culprit is unnecessary materializations, e.g. ToList() or anything that requires traversing the entire enumerator like All(), so if you’re careful to avoid the obvious pitfalls you should be fine.
Setting up state machines and continuations is something C# does when you write generators (with yield) and async methods (with await), but LINQ doesn't do that, particularly.
LINQ the language feature in particular doesn't do any of that sort of thing. As a language feature, LINQ is just the 'query comprehension' syntax, which is the 'from x in y where bar select z' coding form. And from the language's point of view that is just a different way of writing y.Where(x => bar).Select(x => z), which it will then try to compile. If it happens to wind up calling generator methods which implement state machines and continuations, or just simple methods that return ordinary objects, LINQ doesn't care, so long as the types all line up.
The only other thing that confuses matters with LINQ is that those lambdas it wants to compile can match method signatures that have delegate types, or Expression<> types, in which case the lambda doesn't get compiled as executable code, but rather as an expression tree literal, which is how Linq to SQL and friends were built (but again, that's not a 'LINQ' feature - you can assign or pass a lambda as an Expression<> yourself without involving 'LINQ'). And THAT is where LINQ gets a lot of its worst reputation, because that turns out to introduce a ton of complexity and failure modes that aren't the fault of the C# language, except in as much as it made it possible for a library to get involved in interpreting your code's syntax tree at runtime, which may have been a mistake.
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...
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).
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.
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...
Was trying to open your links but I am served an expired tls certificate from Microsoft!
[1] https://en.wikipedia.org/wiki/Erik_Meijer_(computer_scientis...
As an example, a .Where(...) on a List<...> object is exactly what it claims to be: a linear pass through the list. Sometimes that's exactly what you need. Other times, it's more elegant and fast enough to represent an operation as a list comprehension. Finally, sometimes you really do need to eke out more performance. It's only the last case where LINQ is a bad idea.
Yes, but it uses deferred execution, which means that it returns enough information to perform the filter, it doesn't really do much until you start to enumerate the list. If, for instance, you continue to do a Take(5) on the result, the filter is only applied until it finds 5 elements that satisfy the filter (or until there are no more elements).