Open Treit opened 6 months ago
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch See info in area-owners.md if you want to be subscribed.
Duplicate of #30119 and https://github.com/dotnet/runtime/issues/19382#issuecomment-734524103
Since then LINQ has received extensive optimizations. This issue effectively suggests to address the discrepancy between WhereListIterator specialization and the lack of its counterpart on FirstOrDefault.
In particular, it is an issue as the analyzer will actively suggest to simplify expressions of list.Where(condition).FirstOrDefault()
to just list.FirstOrDefault(condition)
. Performance regression in this case will be unexpected and may lead to yet another case of "you have to know how to use the LINQ right", which may not be desirable.
Given that this will be guarded behind similar size opt flag like other iterators for size-sensitive targets, perhaps this can be reconsidered?
. This issue effectively suggests to address the discrepancy between WhereListIterator specialization and the lack of its counterpart on FirstOrDefault.
In particular, the perf improvement discrepancy comes from the WhereIterator types specializing for list and array types, but I don't believe it would be as pronounced if the source enumerable was anything else. The performance of First(OrDefault)
taking predicates can be improved for those cases if we add detection for span-based sources, as shown in this draft PR.
See the benchmark results here:
https://github.com/Treit/MiscBenchmarks/tree/main/WhereFirstOrDefaultVsFirstOrDefault
In a recent code review someone pointed out that we should change calls to
something.Where(somePredicate).FirstOrDefault()
to just besomething.FirstOrDefault(somePredicate)
Much to my surprise, benchmarks show this is significantly slower, at least in the worst case where the thing being searched for is at the end of the list.