<i>In theory</i> .Net 10 should make this obsolete, the headline features[1] are basically all about this. In practice, well, it's heuristics, I'm adding this to a particularly performance sensitive project right now :)<p>Edit: what's also nice is that C# recognizes Linq as a contract. So long as this has the correct method names and signatures (it does), the Linq <i>syntax</i> will light up automatically. You can also use this trick for your own home-grown things (add Select, Join, Where, etc. overloads) if the Linq syntax is something you like.<p>[1]: <a href="https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10/runtime" rel="nofollow">https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotn...</a>
This is great. I've worked on production .NET services and we often had to avoid LINQ in hot paths because of the allocations. Reimplementing functions with for-loops and other structures was time-consuming and error-prone compared to LINQ method chaining. Chaining LINQ methods is extremely powerful; like filter, map, and reduce in JS but with a bunch of other operators and optimizations. I wish more languages had something like it.
This is cool - excited to try it - I would note that I've been a dotnet grunt for almost 15 years now. I am good at it, I know how to use the language, I know the ecosystem - this level of familiarity with the language is just not within my grasp. I can understand the code (mostly) reading it, but I never would have been able to conjure up, let alone implement this. Props to the author.
Could anyone more across the detail of this chime in on what this means for the 'average' .NET developer?<p>I rely heavily on LINQ calls in a .NET (Core) Web App, should I replace these with Zlinq calls?<p>Or is this only helpful in case you want to do LINQ operations on let's say 1000's of objects that would get garbage collected at the end of a game loop?
This is neat, but how does this get away with being zero allocation? It appears to use `Func<T,U>` for its predicates, and since `Func<T>` is a reference type this will allocate. The IL definitely generates definitely seems like it's forming a reference type from what I can tell.
I don't know if anyone remembers expression templates of C++ nowadays. Once upon a time I had written a library of expression templates primitives to chain streams of computations and maps so that the sub-streams do not need to be fully realized in memory - essentially the old idea of Unix pipelines.<p>Writing it was a lot of fun. Debugging compiler errors were a lot less fun because the template language of C++ has no static typing, so errors would be triggered very deep in the expression tree. The expression tree got processed and inlined at compile time so there was no to minimal overhead at runtime.<p>I was very impressed with GCC's inlining and vectorization. Especially the messages that explained why it could not vectorize.
Is it just me, or does this have a case of false advertising?<p>One of the biggest sources of allocation is lambda captures, like when you write something like this<p><pre><code> var myPerson = people.First(x=>x.Name==myPersonName);
</code></pre>
in this case, a phantom object is allocated, that captures the myPersonName variable, for which a delegate is allocated, which is then passed to the First() method, making the number of allocations per call a minimum of 2. I don't see ZLinq doing anything about this.
Interesting approach, but it should be .NET Runtime (or JIT) who would optimize small memory allocations preferring the stack rather than the heap when possible.<p>.NET 10 takes a step in that direction [1].<p>[1] <a href="https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10/runtime#stack-allocation-of-small-arrays-of-value-types" rel="nofollow">https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotn...</a>