Skip to content

Instantly share code, notes, and snippets.

@jbevain
Last active January 9, 2025 22:48
Show Gist options
  • Save jbevain/f24bdafc195672e69b6bbcc203edab4e to your computer and use it in GitHub Desktop.
Save jbevain/f24bdafc195672e69b6bbcc203edab4e to your computer and use it in GitHub Desktop.

For our Visual Studio Code extension, we implemented a debug adapter for our Unity debugger.

Part of the job is translating data structures from our debugger (say a UnityThread), to a DAP Thread. We're using a library that uses List<T> to represent collections.

I originally wrote:

UnityThread[] threads = ...;
List<DAPThread> dapThreads = threads.Select(CreateDAPThread).ToList();

My knee jerk reaction was that this was going to wasteful. We know exactly the number of threads that we need to map, and even though the library we're using a List<T> there's no reason to let the List grow if we know exactly how many items there's going to be.

So I promptly de-LINQ-ified this code:

UnityThread[] threads = ...;
List<DAPThreads> dapThreads = new(threads.Length);
foreach (var thread in threads)
{
    dapThreads.Add(CreateDAPThread(thread));
}

By then I fell good about myself. No more wasting arrays.

But I remembered that last year I found out that today's LINQ is smarter than myself, and is doing some interesting optimizations.

And it turns out that I was wrong once more: today's LINQ has the ability to detect and optimize exactly this pattern.

Screenshot 2025-01-09 at 2 39 31 PM

https://github.com/dotnet/runtime/blob/eb0490e68045f277f976f713f18cb70ecfe12905/src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs#L154-L160

I was been able to revert back to the original implementation knowing it wasn't wasting precious arrays.

Still, it's worth thinking about what's going on behind the scene, as clever as it has become, LINQ is not able to optimize everything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment