Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why there is two completely different version of Reverse for List and IEnumerable?

For the List object, we have a method called Reverse().
It reverse the order of the list 'in place', it doesn't return anything.

For the IEnumerable object, we have an extension method called Reverse().
It returns another IEnumerable.

I need to iterate in reverse order throught a list, so I can't directly use the second method, because I get a List, and I don't want to reverse it, just iterate backwards.

So I can either do this :

for(int i = list.Count - 1; i >=0; i--)

Or

foreach(var item in list.AsEnumerable().Reverse())

I found it less readable than if I have an IEnumerable, just do

foreach(var item in list.Reverse())

I can't understand why this 2 methods have been implemented this way, with the same name. It is pretty annoying and confusing.

Why there is not an extension called BackwardsIterator() in the place of Reverse() working for all IEnumerable?

I'm very interested by the historical reason of this choice, more than the 'how to do it' stuff!

like image 474
Cyril Gandon Avatar asked Sep 12 '12 14:09

Cyril Gandon


3 Answers

It is worth noting that the list method is a lot older than the extension method. The naming was likely kept the same as Reverse seems more succinct than BackwardsIterator.

If you want to bypass the list version and go to the extension method, you need to treat the list like an IEnumerable<T>:

var numbers = new List<int>();
numbers.Reverse(); // hits list
(numbers as IEnumerable<int>).Reverse(); // hits extension

Or call the extension method as a static method:

Enumerable.Reverse(numbers);

Note that the Enumerable version will need to iterate the underlying enumerable entirely in order to start iterating it in reverse. If you plan on doing this multiple times over the same enumerable, consider permanently reversing the order and iterating it normally.

like image 168
Adam Houldsworth Avatar answered Nov 03 '22 19:11

Adam Houldsworth


Write your own BackwardsIterator then!

public static IEnumerable BackwardsIterator(this List lst)
{
    for(int i = lst.Count - 1; i >=0; i--)
    {
        yield return lst[i];
    }
}
like image 42
Anirudha Avatar answered Nov 03 '22 20:11

Anirudha


The existence of List<T>.Reverse long preceded the existence of IEnumerable<T>.Reverse. The reason they are named the same is ... incompetence. It's a horrible botch; clearly the Linq IEnumerable<T> function should have been given a different name ... e.g., Backwards ... since they have quite different semantics. As it is, it lays an awful trap for programmers -- someone might change the type of list from List<T> to, e.g., Collection<T>, and suddenly list.Reverse();, rather than reversing list in place, simply returns an IEnumerable<T> that is discarded. It cannot be overstated just how incompetent it was of MS to give these methods the same name.

To avoid the problem you can define your own extension method

public static IEnumerable<T> Backwards<T>(this IEnumerable<T> source) => source.Reverse();

You can even add a special case for efficient processing of indexable lists:

public static IEnumerable<T> Backwards<T>(this IEnumerable<T> source) =>
    source is IList<T> list ? Backwards<T>(list) : source.Reverse();

public static IEnumerable<T> Backwards<T>(this IList<T> list)
{
    for (int x = list.Count; --x >= 0;)
        yield return list[x];
}
like image 2
Jim Balter Avatar answered Nov 03 '22 18:11

Jim Balter