Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I don't claim to be authoritative with this answer. Instead, it is just my recollection of various discussions I read about iterators and/or my own thoughts... Unfortunately I do not have a list of sources (too long ago) nor can I easily produce one (because even googling up stuff takes lots of time sometimes).</p> <p><strong><code>StopIteration</code></strong></p> <p>The name <code>StopIteration</code> and a lot of the semantics originated from <a href="http://docs.python.org/2/library/exceptions.html#exceptions.StopIteration" rel="nofollow">python</a>.</p> <p><a href="http://www.python.org/dev/peps/pep-0234/" rel="nofollow">PEP 234</a> has some remarks regarding alternative approaches:</p> <blockquote> <ul> <li><p>It has been questioned whether an exception to signal the end of the iteration isn't too expensive. Several alternatives for the StopIteration exception have been proposed: a special value End to signal the end, a function end() to test whether the iterator is finished, even reusing the IndexError exception.</p> <ul> <li><p>A special value has the problem that if a sequence ever contains that special value, a loop over that sequence will end prematurely without any warning. If the experience with null-terminated C strings hasn't taught us the problems this can cause, imagine the trouble a Python introspection tool would have iterating over a list of all built-in names, assuming that the special End value was a built-in name!</p></li> <li><p>Calling an end() function would require two calls per iteration. Two calls is much more expensive than one call plus a test for an exception. Especially the time-critical for loop can test very cheaply for an exception.</p></li> <li><p>Reusing IndexError can cause confusion because it can be a genuine error, which would be masked by ending the loop prematurely.</p></li> </ul></li> </ul> </blockquote> <p><strong><code>hasNext()</code></strong></p> <p>Java's <code>hasNext()</code> is just a "bonus". Java's <code>next()</code>, however, has it's own flavor of <code>StopIteration</code> called <a href="http://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html#next%28%29" rel="nofollow"><code>NoSuchElementException</code></a>.</p> <p><code>hasNext()</code> is hard, if not impossible, to implement, which is best demonstrated with e.g. the following generator:</p> <pre><code>var i = 0; function gen() { yield doSomethingDestructive(); if (!i) { yield doSomethingElse(); } } </code></pre> <p>How would you implement <code>hasNext()</code> for that? You cannot simply "peek" into the generator, because that would actually execute <code>doSomethingDestructive()</code>, which you didn't intend to do or else you would have called <code>next()</code> in the first place.</p> <p>So you'd have to write some code analyzer that has to always reliably proof that a given code when run with a certain state will always result in either a yield or no yield (halting problem). So even if you could write something like that, the state may still change between <code>.hasNext()</code> and a subsequent <code>.next()</code>.</p> <p>What would <code>hasNext()</code> return in the following example:</p> <pre><code>var g = gen(); g.next(); if (g.hasNext()) { ++i; alert(g.next()); } </code></pre> <p>At that point of time <code>true</code> would be the right answer. However, the subsequent <code>.next()</code> would throw, and the user would probably have a hard time figuring out why...</p> <p>You could tell people: "Don't do the following things in your iterator implementation" (a contract). Which people will routinely break and complain.</p> <p>So in my humble opinion, <code>hasNext()</code> was ill-conceived and makes it too easy to write wrong code.</p> <p><em><strong><code>.MoveNext()</code></em></strong></p> <p><code>C#</code> is pretty much the same as <code>.next()</code>, just that the return value indicates if there was actually a next item instead of or the lack of an exception.</p> <p>There is one important difference, however: You need to store the current item in the iterator itself, e.g. <code>.Current</code> in C#, which may prolong the life-time of the current item unnecessarily: </p> <pre><code>var bufferCtor = (function gen() { for(;;) { yield new ArrayBuffer(1&lt;&lt;20); // buffer of size 1 megabyte } })(); setInterval(function() { // MoveNext scheme bufferCtor.MoveNext(); // Not actually Javascript var buf = bufferCtor.Current; // Not actually Javascript // vs. StopIteration scheme var buf = bufferCtor.next(); }, 60000); // Each minute </code></pre> <p>OK, that example is a little contrived, but I'm sure there are actual use cases where a generator/iterator would return something talking up a lot of space or otherwise occupying resources.</p> <p>In the <code>StopIteration</code> scheme, <code>buf</code> can be garbage-collected as soon as it goes out of scope. In <code>.MoveNext()</code>, it cannot be garbage-collected until <code>.next()</code> is called again, because <code>.Current</code> will still hold a reference to it.</p> <p><strong>Conclusion</strong></p> <p>In my opinion, of the presented alternatives, the <code>StopIteration</code> one is the least error prone and least ambiguous approach. And if I recall correctly, the python and es-6 people thought about the same.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload