Other languages implement iterators a coroutines or threads. In both cases, the iterator has its own execution path separate from the execution path of the code that is using the iterator. Typical use has a single method that produces all of the items to iterate over in a single invocation. With coroutines, when an iterator produces an item, it transfers control to the code that is using the iterator through a special transfer statement. When that code needs yet another item, it transfers control back to the iterator with another transfer statement. That transfer mechanism can be simulated by threads that block and unblock each other.
The important distinction between iterators-as-objects implementation and the iterators-as-threads implementation is that in the former case the items must be produced over several different invocations of next, while in the latter case they are produced during a single invocation. This makes it easier to do complex iterations, such as iterating through the nodes in a binary search tree. Such a task be easily performed by a single invocation of a recursive method. Accomplishing that with several sequential calls to next would require that the iterator remember its path to the current point in the tree -- essentially it has to keep track of the information that recursion keeps track of automatically.
We should be able to create different kinds of iterators by creating subclasses of PIterator. A PIterator object should be started as a separate thread that executes the code that produces the items. That code should invoke yield when it has produced an item and end after it has produced all of the items. The thread that is using the iterator will invoke hasNext and next to determine if there is a next item and to retrieve the next item.
The two threads should coordinate their execution as follows: if a thread invokes hasNext or next before the iterator has produced the next item or determines that there are no more items, the invoking thread should block until yield or end is invoked to produce an item or to indicate that no more items will be available. If the iterator invokes yield before the thread using it invokes next, the iterator should block until the thread using it invokes next.
The Java code is in a Java archive that contains
In both languages there is a sample subclass that iterates over all permutations of a given string, which is reasonably easy to do with recursion (it can also be done iteratively with a little more difficulty).