views:

238

answers:

4

Basically I am wondering why MS decided to implement an enumerator that only supports going forward: MoveNext().

Is it not more flexible to also enforce MovePrevious for this widely used interface throughout the .NET framework?

I can imagine it making the Linq.Reverse far easier to implement for MS and more efficient in performance, but I am not sure if this makes other things slower or puts a massive overhead on everything else.

Anyone with more knowledge in this subject can give more info on this please? i.e. the pros and cons of having or not having MovePrevious in IEnumerable/IEnumerable<T>.

+5  A: 

There are many types of data where it does not make sense to have a MovePrevious. For example, if you are receiving data from a network connection, providing a MovePrevious would require buffering the entire stream just in case you called that method. This would waste huge amounts of memory.

Having said that, it might be useful to have a different type which supported both MoveNext and MovePrevious (a doubly linked list could support this, for example).

Mark Byers
ITraversable<T>? :)
Mark Simpson
+15  A: 

IEnumerable[<T>] represents a sequence of data, not a random-access list. Not all sequences can be reversed, or even replayed. Sequences based on network streams, database access, etc - or this beauty:

IEnumerable<int> GetData() {
    Random rand = new Random();
    while(true) { yield return rand.Next(); }
}

The best you can do is start again - not by calling Reset() (which is deprecated), but by getting a fresh enumerator instead.

Even without Random it is trivial to come up with simple sequences that cannot be reversed (without buffering and reversing the buffer). For what you want, consider looking at IList[<T>] instead - you can access data via the indexer in any order.

Marc Gravell
Thanks Marc, if you are buffering which could also be another IEnumerable<T>, it might be an overhead not everyone would want, right?
Joan Venge
Indeed - don't call buffering operations (`Reverse`, `OrderBy`, `GroupBy`) if you have a large (or infinite) sequence ;-p
Marc Gravell
A: 

It's to do with the pattern regarding "yield". Effectively enumerators are the simplest possible collection, you simply start at the front and take until the very end. This means that they code to implement the enumeration is extremely simple.

Also you can have functional code using iterators which never "end" as such, for instance

yield value++;

You will simply receive incrementing numbers until you stop.

Spence
In fact there needs not be an "end" at all. Consider `while (true) { yield return Random.Next(); }`.
Pavel Minaev
The design of IEnumerator predates yield by several years.
Marc Gravell
`yield` just makes it easier to implement it, but the concept (of "simplest possible collection") is just as old. Could be worded better, though.
Pavel Minaev
I use the best way of describing the concept using the advances that we have made in the language. Many of the collection concepts in .Net were invented years and in some cases decades before. Doesn't make it incorrect to use them in a description though.
Spence
+1  A: 

Usage convenience isn't the only factor involved when designing an interface ... you have to take into account how versatile it'll be and how what constraints you are adding to it.

There are sequences that can't be replayed, and you'd be adding a lot of unnecessary requirements to implementing it.

There are other interfaces besides it, like IList, IQueryable. Using the most appropriate for the scenario, also communicates the type of usage that it should have.

eglasius