1.7

  • Revision slug: Talk:JavaScript/New_in_JavaScript/1.7
  • Revision title: 1.7
  • Revision id: 124970
  • Created:
  • Creator: Marienz
  • Is current revision? No
  • Comment Add a request for a warning about "for each" on arrays being unsafe

Revision Content

Spent Iterators Should Not Throw an Exception

Exceptions should be used when there is a runtime error, not when a normal termination condition occurs. When calling it.next() on an iterator, the return value of that call should indicate the status of the iterator. The value returned should probably be null, but I'd be willing to entertain arguments for false, undefined, or something of the sort.

Throwing an exception to handle a normal case like a spent iterator will cause developers to litter code with try/catch blocks and create an enormous amount of unnecessary complexity. Code like the following should be possible in the spirit of JS and other languages that support similar constructs:

while ((item = it.next()) !== null)
{
    print(item);
}

h3h 16:56, 1 June 2006 (PDT)

The problem with returning a special value is that whatever value you choose can't be produced by the iterator.

The design of this feature is very similar to Python's, and the same discussion happened between the Python developers in 2001. They reached the conclusion that an exception is the best way to handle termination of an iterator. See python-dev threads such as "why not "return StopIteration"?", which quotes from the Python Enhancement Proposal that introduced iterators, PEP 234.

Experience with this design in Python has shown that developers don't often have to explicitly call the next method or catch the exception; iterators are usually iterated over in for loops, or passed to functions. Your example would usually be written in JS as

for (var item in it) {
    print(item);
}

or even

printAll(it);

Deltab 08:48, 30 June 2006 (PDT)

I was looking at the yield statement, and it reminded me of the lack of a sleep/suspend/wait function, which makes a lot of code much more painful than it needs to be. Are there any plans to add this kind of function to 1.7?

It would be especially nice if there were a WaitFor(evt) function and a corresponding NotifyThat(evtHappened) so that threads could simply wait until another thread (or the human user!) was finished.

(Apologies if this is the wrong place to raise this.)

--Voracity 00:45, 25 July 2006 (PDT)

Bug in "Row capture and record updating" example?

The final example, it's not clear how newPersonRecord could include the property "name", as "name" was never a property of z (from the previous example).

Should the example use personRecord instead of z?

Tag 22:07, 26 July 2006 (PDT)

Syntax for replacing native iterators?

If you wish to provide a custom iterator, you should override the getter for __iterator__ to return an instance of your custom iterator.

I'm having trouble finding the precise syntax to override these native iterators.

Let's say I want to rewrite the DOM HTMLCollection iterator to return only nodes and ignore the builtin properties (length, item, and namedItem). My code looks something like this:

    var DOMIterator = function(nodeList) {
      var len  = nodeList.length, i = 0, ret;
      for (i = 0; i < len; i++) {
        yield [i, nodeList[i]];
      }
      throw StopIteration;
    };
    
    var nodes = document.getElementsByTagName('p');
    
    nodes.__defineGetter__("__iterator__", function() {
      return new DOMIterator(this);
    });
    

When I evaluate nodes.__iterator__, I get {{mediawiki.external('object Generator')}}. But when I try for (var x in nodes) { /* do something */ }, I get a TypeError ("nodes has invalid __iterator__ value ({})").

I'm sure I've overlooked something simple, but I've tried a crapload of variations on this theme — making the iterator return a function, removing the yield statement and defining an ordinary next method, etc. What am I doing wrong? Savetheclocktower 11:46, 29 July 2006 (PDT)

See --Nickolay 16:45, 29 July 2006 (PDT)
Your problem is that you used __defineGetter__ to set the value of nodes.__iterator__ to be new DOMIterator(this) (incidentally, I don't think the new is needed there, and I'm not even sure what the new operator applied to a function which defines a generator like that even means).
The __iterator__ property should be a reference to a function which returns DOMIterator(this). This is somewhat counterintuitive (or at least it was to me when I was first playing around with this), but consider it this way: if __iterator__ were actually a Generator, that would mean you could only iterate over an object once. __iterator__ needs to be implemented via a getter-style method, and since __defineGetter__ is Mozilla-specific, that method of implementation's out, and thus only a standard JS function will do.
As for iterating over only the items in an HTMLCollection, I believe there's a bug that keeps this from working correctly (which is demonstrated as a reduced testcase in the newsgroup post mentioned above); see my response to that post, as well. --Waldo 02:24, 30 July 2006 (PDT)
Cool, thanks. So should that passage read "you should override the __iterator__ property to return an instance..."? I don't understand why it's referred to as a getter in that context.
At any rate, I'd stumbled upon the correct method for this a while back, but didn't realize it because of the bug you mention -- it was iterating over my generator and all remaining properties, so I couldn't distinguish it from an ordinary for..in. Savetheclocktower 16:33, 31 July 2006 (PDT)

On generators and iterators

Some useful links:

--Nickolay 07:42, 30 July 2006 (PDT)

Ignoring some returned values

I got email from Brendan last night indicating this is in fact supported after all in JavaScript 1.7, so I've restored this section to the documentation.--Sheppy 12:42, 31 October 2006 (PST)

Reserved Words

It appears that handling of reserved words is different between 1.6 and 1.7. I developed an application that used an RPC object (using the Dojo toolkit) that had the delete method, it worked fine in FF2 (using 1.7) but caused a Syntax Error in FF1.5 (using 1.6). delete is of course a reserved word. Changing the method name to "remove" and it works just fine. Just posting this as an advisory in case anyone is facing a similar issue MrWeeble 07:38, 1 December 2006 (PST)

An example of let constructs

I added another example of let definitions. I hope that this example explains part of the reasons let constructs are useful. Feel free to edit it. To avoid any doubts of copyright infringement, I copied the code from my own web page http://homepage2.nifty.com/polytope/javascript-let/ (in Japanese). --fcp 16:36, 1 June 2007 (PDT)

for each on arrays with destructuring assignment still unsafe

Other pages in this wiki discussing for each repeatedly state using it on an Array is unsafe because it picks up additions to Array.prototype (which even a file in the Firefox 2.0.x source tree (look for lang.js iirc) messes with!). Because this page does not have that warning I assumed this style of looping was now "safe". This does not seem to be the case:

   Array.prototype.spork = 42;
   Array.prototype.owner = {name: 'us'};
   var people = [{name: 'me'}];
   for each (var {name: n} in people) {
       alert(n);
   }

produces "me", "undefined", "us" ("undefined" because (42).name is undefined), which I still think is surprising behaviour. However I am pretty much a javascript newbie, so I think I should not add this to the actual page unless others agree.

Revision Source

<h3 name="Spent_Iterators_Should_Not_Throw_an_Exception"> Spent Iterators Should Not Throw an Exception </h3>
<p>Exceptions should be used when there is a runtime <b>error</b>, not when a normal termination condition occurs. When calling <code>it.next()</code> on an iterator, the <i>return value</i> of that call should indicate the status of the iterator. The value returned should probably be <code>null</code>, but I'd be willing to entertain arguments for <code>false</code>, <code>undefined</code>, or something of the sort.
</p><p>Throwing an exception to handle a normal case like a spent iterator will cause developers to litter code with <code>try</code>/<code>catch</code> blocks and create an enormous amount of unnecessary complexity. Code like the following should be possible in the spirit of JS and other languages that support similar constructs:
</p>
<pre>while ((item = it.next()) !== null)
{
    print(item);
}</pre>
<p>— <a href="User:H3h">h3h</a> 16:56, 1 June 2006 (PDT)
</p><p>The problem with returning a special value is that whatever value you choose can't be produced by the iterator.
</p><p>The design of this feature is very similar to Python's, and the same discussion happened between the Python developers in 2001. They reached the conclusion that an exception is the best way to handle termination of an iterator. See python-dev threads such as "<a class="external" href="http://mail.python.org/pipermail/python-dev/2001-June/015508.html">why not "return StopIteration"?</a>", which quotes from the Python Enhancement Proposal that introduced iterators, <a class="external" href="http://www.python.org/dev/peps/pep-0234/">PEP 234</a>.
</p><p>Experience with this design in Python has shown that developers don't often have to explicitly call the <code>next</code> method or catch the exception; iterators are usually iterated over in <code>for</code> loops, or passed to functions. Your example would usually be written in JS as
</p>
<pre>for (var item in it) {
    print(item);
}</pre>
<p>or even
</p>
<pre>printAll(it);</pre>
<p>— <a href="User:Deltab">Deltab</a> 08:48, 30 June 2006 (PDT)
</p><p>I was looking at the yield statement, and it reminded me of the lack of a <code>sleep/suspend/wait</code> function, which makes a lot of code much more painful than it needs to be. Are there any plans to add this kind of function to 1.7?
</p><p>It would be especially nice if there were a <code>WaitFor(evt)</code> function and a corresponding <code>NotifyThat(evtHappened)</code> so that threads could simply wait until another thread (or the human user!) was finished.
</p><p>(Apologies if this is the wrong place to raise this.)
</p><p>--<a href="User:Voracity">Voracity</a> 00:45, 25 July 2006 (PDT)
</p>
<h3 name="Bug_in_.22Row_capture_and_record_updating.22_example.3F"> Bug in "Row capture and record updating" example? </h3>
<p>The final example, it's not clear how <code>newPersonRecord</code> could include the property "name", as "name" was never a property of <code>z</code> (from the previous example).
</p><p>Should the example use <code>personRecord</code> instead of <code>z</code>?
</p><p><a href="User:Tag">Tag</a> 22:07, 26 July 2006 (PDT)
</p>
<h3 name="Syntax_for_replacing_native_iterators.3F"> Syntax for replacing native iterators? </h3>
<blockquote>If you wish to provide a custom iterator, you should override the getter for __iterator__ to return an instance of your custom iterator.</blockquote>
<p>I'm having trouble finding the precise syntax to override these native iterators.  
</p><p>Let's say I want to rewrite the DOM <code>HTMLCollection</code> iterator to return only nodes and ignore the builtin properties (length, item, and namedItem).  My code looks something like this:
</p>
<pre>    var DOMIterator = function(nodeList) {
      var len  = nodeList.length, i = 0, ret;
      for (i = 0; i &lt; len; i++) {
        yield [i, nodeList[i]];
      }
      throw StopIteration;
    };
    
    var nodes = document.getElementsByTagName('p');
    
    nodes.__defineGetter__("__iterator__", function() {
      return new DOMIterator(this);
    });
    
</pre>
<p>When I evaluate <code>nodes.__iterator__</code>, I get <code>{{mediawiki.external('object Generator')}}</code>.  But when I try <code>for (var x in nodes) { /* do something */ }</code>, I get a <code>TypeError</code> ("<code>nodes has invalid __iterator__ value ({})</code>").
</p><p>I'm sure I've overlooked something simple, but I've tried a crapload of variations on this theme — making the iterator return a function, removing the <code>yield</code> statement and defining an ordinary <code>next</code> method, etc.  What am I doing wrong? <a href="User:Savetheclocktower">Savetheclocktower</a> 11:46, 29 July 2006 (PDT)
</p>
<dl><dd> See <a class="external" href="http://groups.google.com/group/mozilla.dev.tech.js-engine/browse_thread/thread/d7571ff410e67528/24e39cbd75344230#24e39cbd75344230"> --</a><a href="User:Nickolay">Nickolay</a> 16:45, 29 July 2006 (PDT)
</dd></dl>
<dl><dd> Your problem is that you used __defineGetter__ to set the value of nodes.__iterator__ to be <code>new DOMIterator(this)</code> (incidentally, I don't think the <code>new</code> is needed there, and I'm not even sure what the <code>new</code> operator applied to a function which defines a generator like that even means). <br> The <code>__iterator__</code> property should be a reference to a function which returns <code>DOMIterator(this)</code>.  This is somewhat counterintuitive (or at least it was to me when I was first playing around with this), but consider it this way: if <code>__iterator__</code> were actually a Generator, that would mean you could only iterate over an object once.  <code>__iterator__</code> needs to be implemented via a getter-style method, and since <code>__defineGetter__</code> is Mozilla-specific, that method of implementation's out, and thus only a standard JS function will do. <br> As for iterating over only the items in an HTMLCollection, I believe there's a bug that keeps this from working correctly (which is demonstrated as a reduced testcase in the newsgroup post mentioned above); see my response to that post, as well. --<a href="User:Waldo">Waldo</a> 02:24, 30 July 2006 (PDT)
</dd></dl>
<dl><dd><dl><dd> Cool, thanks.  So should that passage read "you should override the <code>__iterator__</code> property to return an instance..."?  I don't understand why it's referred to as a getter in that context.
</dd></dl>
</dd></dl>
<dl><dd><dl><dd> At any rate, I'd stumbled upon the correct method for this a while back, but didn't realize it because of the bug you mention -- it was iterating over my generator <em>and</em> all remaining properties, so I couldn't distinguish it from an ordinary <code>for..in</code>.  <a href="User:Savetheclocktower">Savetheclocktower</a> 16:33, 31 July 2006 (PDT)  
</dd></dl>
</dd></dl>
<h3 name="On_generators_and_iterators"> On generators and iterators </h3>
<p>Some useful links:
</p>
<ul><li> <a href="en/New_in_JavaScript_1.7#Generators_and_iterators">New_in_JavaScript_1.7#Generators_and_iterators</a>
</li><li> {{template.Bug("326466#c39")}} - brendan's description of the feature.
</li><li> PEPs: <a class="external" href="http://www.python.org/dev/peps/pep-0234/">234: Iterators</a>, <a class="external" href="http://www.python.org/dev/peps/pep-0255/">255: Generators</a>, <a class="external" href="http://www.python.org/dev/peps/pep-0342/">Coroutines via Enhanced Generators</a>
</li><li> Weird behavior with a custom iterator: <a class="external" href="http://groups.google.com/group/mozilla.dev.tech.js-engine/browse_thread/thread/d7571ff410e67528/24e39cbd75344230#24e39cbd75344230"> / {{template.Bug(346021)}}
</a></li></ul><a class="external" href="http://groups.google.com/group/mozilla.dev.tech.js-engine/browse_thread/thread/d7571ff410e67528/24e39cbd75344230#24e39cbd75344230">
</a><p><a class="external" href="http://groups.google.com/group/mozilla.dev.tech.js-engine/browse_thread/thread/d7571ff410e67528/24e39cbd75344230#24e39cbd75344230">--</a><a href="User:Nickolay">Nickolay</a> 07:42, 30 July 2006 (PDT)
</p>
<h3 name="Ignoring_some_returned_values">Ignoring some returned values</h3>
<p>I got email from Brendan last night indicating this is in fact supported after all in JavaScript 1.7, so I've restored this section to the documentation.--<a href="User:Sheppy">Sheppy</a> 12:42, 31 October 2006 (PST)
</p>
<h3 name="Reserved_Words"> Reserved Words </h3>
<p>It appears that handling of reserved words is different between 1.6 and 1.7. I developed an application that used an RPC object (using the Dojo toolkit) that had the delete method, it worked fine in FF2 (using 1.7) but caused a Syntax Error in FF1.5 (using 1.6). delete is of course a reserved word. Changing the method name to "remove" and it works just fine. Just posting this as an advisory in case anyone is facing a similar issue <a href="User:MrWeeble">MrWeeble</a> 07:38, 1 December 2006 (PST)
</p>
<h3 name="An_example_of_let_constructs"> An example of <code>let</code> constructs </h3>
<p>I added another example of <code>let</code> definitions. I hope that this example explains part of the reasons <code>let</code> constructs are useful. Feel free to edit it. To avoid any doubts of copyright infringement, I copied the code from my own web page http://homepage2.nifty.com/polytope/javascript-let/ (in Japanese). --<a href="User:Fcp">fcp</a> 16:36, 1 June 2007 (PDT)
</p>
<h3 name="for_each_on_arrays_with_destructuring_assignment_still_unsafe"> <code>for each</code> on arrays with destructuring assignment still unsafe </h3>
<p>Other pages in this wiki discussing <code>for each</code> repeatedly state using it on an <code>Array</code> is unsafe because it picks up additions to <code>Array.prototype</code> (which even a file in the Firefox 2.0.x source tree (look for lang.js iirc) messes with!). Because this page does not have that warning I assumed this style of looping was now "safe". This does not seem to be the case:
</p><p><code>
</code></p>
<pre class="eval">   Array.prototype.spork = 42;
   Array.prototype.owner = {name: 'us'};
   var people = [{name: 'me'}];
   for each (var {name: n} in people) {
       alert(n);
   }
</pre>
<p>
</p><p>produces "me", "undefined", "us" ("undefined" because <code>(42).name</code> is undefined), which I still think is surprising behaviour. However I am pretty much a javascript newbie, so I think I should not add this to the actual page unless others agree.
</p>
Revert to this revision