Beware of the big bad LINQ

Pop quiz – given:

    Stack<int> stack;

what is the difference between:

    return stack.Count;


    return stack.Count();

Is it:

  1. No difference: both return the number of elements on the specified stack
  2. The first is a property of Stack<T>, while the second is a LINQ extension method
  3. The first uses 3 IL instructions, while the second uses 34
  4. The first runs in constant time, while the second is O(n)
  5. The second version generates garbage, while the first does not

Answer: all of the above.

The extension methods defined in the System.Linq namespace are tremendously powerful, and can be a thing of beauty when used wisely, but with great power comes great responsibility. I find it a more than a little scary that such a subtle code change can have such dramatic performance implications!

Comments (8)

  1. onovotny says:

    In .NET 4.0, the Count() method will check for the ICollection interface in addition to ICollection<T> and use Count on it.  The result will be much faster, as well as being in constant time.

  2. Scott Wendt says:

    This is the sort of thing that a tool like resharper should check for and warn about. Other static analysis could also catch this. I do like seeing the comment about .NET 4.0 fixing this oversite in the libraries theselves though.

    I think in general we need to be careful of where the code we are calling is coming from now that extension methods exist. Pre-link the () at the end would have generated a nice compiler error for you. Maybe VS could highlight extension method calls in a different color so that we know they aren’t normal class methods or something.

    Sorry this is a bit of a ramble just typing as I think 🙂

  3. Martin Sherburn says:

    @Scott: Extension methods do show up with a different icon in the auto-complete list so that you know it’s an extension.

    I find it quite surprising that Linq is actually available on the Xbox considering that methods like Enum.GetNames haven’t been included along with a few other seemingly random things. I use Linq quite a lot for my job and I like it but I wouldn’t use it for XNA because of the performance implications.

  4. TechNeilogy says:

    I think it comes down to an education thing.  Such features are fine if understood and used appropriately.

    This is the kind of thing I’ve seen happen multiple times in the field.  A dev team goes wild on ease of use features without understanding the consequences of using them in inappropriate or unnecessary situations.  Next thing you know the app bogs down and consumes all the memory on the machine.


  5. Neil says:

    Speaking of .net 4, I’ll be interested to see if dynamic makes it over to Xbox……..

  6. @onovotny: The Count() checks ICollection.Count in .NET 3.5 SP1 as well, making O(1).

    @Scott: Extension methods add virtually zero overhead, so I’m not sure why a static analysis should flag them, they’re a good practise not a bad one.

    @Neil: Actually, since LINQ Count() operates in O(1) time for ICollections, it was implemented 100% fine. If you look at the hot path, they’ve added 3 IL instructions, hardly a nightmare.

  7. ShawnHargreaves says:

    > Extension methods add virtually zero overhead, so I’m not sure why a static analysis should flag them, they’re a good practise not a bad one.

    Agreed. There’s nothing wrong with extension methods per se: it’s equally possible to write an instance method that looks innocuous but has surprising perf characteristics!

    My point was more about the increasingly high level of abstraction provided by technologies such as LINQ, rather than the fact that these happen to be implemented as extension methods. Increased abstraction is a good thing for all kinds of reasons, but it does make perf less obvious and harder to reason about just from reading code.

  8. haxpor says:

    Thanks for this kind of useful information.

    I see lots of methods included which can be seen when auto-complete shows up while you are including LINQ.

    Agree on the increasingly high level on top of the simple one, I avoid using it all the time when developing game or doing some test bed. But for some time, very rare, I have to use it for simplicity. I need to go back and check out my code to increase perf!!


Skip to main content