score:2

Accepted answer

My guess, which is a shot in dark, as any answer you might get: optimizing in the predicate case would cause more side effects. Optimization generally causes a side-effect because the GetEnumerator() of IEnumarble is not called. But in the predicate case, you can observe from the outside that it's not called in order. One might write a predicate that expects the iteration to happen in order, and going backwards would break that.

score:0

Except when an implementation of IList<T> contains a very small number of items, optimizing the non-predicate Last to return theList[theList.Count()-1] is unlikely to be slower than simply enumerating from the start; it's unlikely that for any reasonable IList<T> implementation it will be much slower. Even though the time required for some implementations of IList<T> to find an item by index may be significantly longer than the average per-item time required to fetch data sequentially (perhaps by an order of magnitude, though probably not two), reading one item by index will generally take much less time than reading every item sequentially (random access generally won't be much slower than sequential access unless a collection is big; if in a 1,000,000-item collection the cost to read an item by index is 1,000 times the per-item time required for sequential access [an atypically-large penalty], that would still be 1,000 times as fast as reading every item).

When using Last with a predicate, there's no guarantee how many items will need to be examined. If random access takes longer than sequential access (common), and the last match happens to occur early in the list (highly plausible), then processing the list from the start will be faster than processing from the end. Given that it would not be unreasonable for an IList<T> implementation to take ten times as long to perform a random access as a sequential fetch, the "optimization" of reading from the back could end up making things an order of magnitude slower than "unoptimized" code that read sequentially.

If IList<T> provided more options for reading out data, and/or included properties which roughly described the relative costs of different operations, then a Last method could be optimized to examine list items in some other sequence, but absent such features it's better for the method to use a straightforward approach whose behavior is predictable if uninspiring, than one which tries to be clever but might sometimes perform much worse.


Related Articles