none
Adapting IEnumerable<T> to Java-style IIterator<T> RRS feed

  • Question

  • Note: My main concern is obtaing a good adapter class/methodology for any IEnumerable<T> to an IIterator<T>. If anyone knows of one, feel free to post without reading all the background below.

    I have checked similar questions and not found any that quite deal with this particular angle of the problem (that is, the specific problem of adapting cleanly an IEnumerator to an IIterator).

    I am currently converting a (fairly large) Java project to C#. As anyone with experience of doing this may be aware, although visually the code between Java and C# looks similar there are some significant functional differences between Java and C#. C# is a tighter language, mainly I think for readability.

    One of the core differences between Java and C# is IIterator in Java and IEnumerable in C#.

    I am trying to adapt IEnumerator to IIterator. The problem is IIterator in Java has a .hasNext() method - which checks whether a next element is available without actually advancing the iterator to the next element - whereas IEnumerable has only the ability to return the current element in the iteration; and cannot inform you whether a next element is available without actually advancing the iterator to the next element (you cannot go back).

    My question is (and this may be due to my inexperience with Java) - whereas I can see IEnumerator may be able to iterate across all elements in a forward-only, readonly way without first evaluating all elements in the IEnumerator, how can IIterator provide the 'peek ahead' (.hasNext()) functionality without having a read-ahead evaluation requiring some or all elements in the iteration to be executed ahead of the current element? This seems to be self-defeating, in that the main iterator interface IIterator requires read-ahead - which is by concept incompatible with element-by-element iteration?

    I ask this particular question because, currently, in order to adapt an IEnumerator and return an IIterator, I need to first execute the IEnumerator in order to provide a .HasNext property - which seems to defeat the purpose of a IEnumerator which does not require all elements to be evaluated before iterating through in a forward-only manner.

    Is this just some misunderstanding on the purpose of an IIterator that I have, in that they are not meant to be equivalent? For example if I implemented an IIterator for reading the rows in a data table, it seems to me I would have to at least execute a cursor read of the next row on advancing through each element in the iterator to provide the HasNext functionality?

    In sum, if anyone has a sound adaption of IEnumerator to IIterator I would be grateful if they would share.

    Thanks

    Markos101



    • Edited by Markos101 Saturday, March 22, 2014 10:14 AM
    Saturday, March 22, 2014 9:25 AM

Answers

  • Hmm, lots of question and I'm not quite sure which is the main one. Let's start with an example that shows how to implement an IIterator like interface when you have an IEnumerator:

    interface IIterator<T> {
        bool HasNext();
        T Next();
    }
    
    class IteratorAdapter<T> : IIterator<T> {
        private readonly IEnumerator<T> e;
        private bool? hasNext;
    
        public IteratorAdapter(IEnumerable<T> e) {
            this.e = e.GetEnumerator();
        }
    
        public bool HasNext() {
            if (hasNext == null) {
                // we have no idea if there's a next element or not
                // we have to call MoveNext and remember its result
                hasNext = e.MoveNext();
            }
    
            return hasNext.Value;
        }
    
        public T Next() {
            // call HasNext, it will call MoveNext if needed
            if (!HasNext())
                throw new InvalidOperationException();
    
            // we have to clear hasNext so next time it is called MoveNext is also called
            hasNext = null;
    
            return e.Current;
        }
    }
    
    class Program {
        static void Main() {
            var iter = new IteratorAdapter<int>(new List<int> { 1, 2, 3 });
    
            while (iter.HasNext()) {
                var i = iter.Next();
                Console.WriteLine("{0} {1}", i, iter.HasNext());
            }
        }
    }
    

    It's obvious that HasNext has to call MoveNext, there's no way around that. And once it calls MoveNext it has to remember the result until Next is called.

    Now, let's implement an Iterator for the List class instead of trying to adapt an existing enumerator:

    class ListIterator<T> : IIterator<T> {
        private readonly List<T> list;
        private int index;
    
        public ListIterator(List<T> list) {
            this.list = list;
        }
    
        public bool HasNext() {
            return index < list.Count;
        }
    
        public T Next() {
            if (!HasNext())
                throw new InvalidOperationException();
    
            return list[index++];
        }
    }

    Here HasNext is much simpler because, it only needs to check the current index against the list count. This should answer one of your questions, "how can IIterator provide the peek ahead functionality without having a read-ahead evaluation...".

    "Is this just some misunderstanding on the purpose of an IIterator that I have, in that they are not meant to be equivalent? ..."

    Well, when used with collections such as List the differences between IIterator and IEnumerator are pretty much non existent, as shown above there's no actual read ahead going on.

    Now, if you're trying to iterate/enumerate something other than a collection then yes, IIterator and IEnumerator aren't 100% equivalent. But I think this will be relevant only in the particular case where you want to call hasNext without also calling next. In my experience that's rarely the case.

    Saturday, March 22, 2014 10:41 AM
    Moderator

All replies

  • Hmm, lots of question and I'm not quite sure which is the main one. Let's start with an example that shows how to implement an IIterator like interface when you have an IEnumerator:

    interface IIterator<T> {
        bool HasNext();
        T Next();
    }
    
    class IteratorAdapter<T> : IIterator<T> {
        private readonly IEnumerator<T> e;
        private bool? hasNext;
    
        public IteratorAdapter(IEnumerable<T> e) {
            this.e = e.GetEnumerator();
        }
    
        public bool HasNext() {
            if (hasNext == null) {
                // we have no idea if there's a next element or not
                // we have to call MoveNext and remember its result
                hasNext = e.MoveNext();
            }
    
            return hasNext.Value;
        }
    
        public T Next() {
            // call HasNext, it will call MoveNext if needed
            if (!HasNext())
                throw new InvalidOperationException();
    
            // we have to clear hasNext so next time it is called MoveNext is also called
            hasNext = null;
    
            return e.Current;
        }
    }
    
    class Program {
        static void Main() {
            var iter = new IteratorAdapter<int>(new List<int> { 1, 2, 3 });
    
            while (iter.HasNext()) {
                var i = iter.Next();
                Console.WriteLine("{0} {1}", i, iter.HasNext());
            }
        }
    }
    

    It's obvious that HasNext has to call MoveNext, there's no way around that. And once it calls MoveNext it has to remember the result until Next is called.

    Now, let's implement an Iterator for the List class instead of trying to adapt an existing enumerator:

    class ListIterator<T> : IIterator<T> {
        private readonly List<T> list;
        private int index;
    
        public ListIterator(List<T> list) {
            this.list = list;
        }
    
        public bool HasNext() {
            return index < list.Count;
        }
    
        public T Next() {
            if (!HasNext())
                throw new InvalidOperationException();
    
            return list[index++];
        }
    }

    Here HasNext is much simpler because, it only needs to check the current index against the list count. This should answer one of your questions, "how can IIterator provide the peek ahead functionality without having a read-ahead evaluation...".

    "Is this just some misunderstanding on the purpose of an IIterator that I have, in that they are not meant to be equivalent? ..."

    Well, when used with collections such as List the differences between IIterator and IEnumerator are pretty much non existent, as shown above there's no actual read ahead going on.

    Now, if you're trying to iterate/enumerate something other than a collection then yes, IIterator and IEnumerator aren't 100% equivalent. But I think this will be relevant only in the particular case where you want to call hasNext without also calling next. In my experience that's rarely the case.

    Saturday, March 22, 2014 10:41 AM
    Moderator
  • Dot net is Not awesome
    Monday, May 25, 2015 12:03 PM