1.7

  • Revision slug: Talk:JavaScript/New_in_JavaScript/1.7
  • Revision title: 1.7
  • Revision id: 124978
  • Created:
  • Creator: Yuichirou
  • Is current revision? No
  • Comment /* What does "completion value" mean? */

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. Marienz 09:31, 27 August 2007 (PDT)

Yep, this could be mentioned. --Nickolay 22:28, 8 September 2007 (PDT)

Another let (and destructuring assignment) example

I agree with the JavaScript_style_guide that it is useful to "wrap functions and variables inside an object with a unique name to avoid conflicting with existing or future function and variable names", but having to refer to the name of that wrapper object all over the place is annoying (since it should have a nontrivial name to be of use for preventing collisions). It helps if you can refer to this instead of the full name, but that does not work from event handlers unless you do something like:

// This is not real-world code, obviously :P
var ReallyLongNonClashingName = {
    data: 1,

    onClick: function(evt) {
        alert(this.data);
    }
};

// but this is (except for the ReallyLongNonClashingName)
for (let [name, value] in ReallyLongNonClashingName) {
    if (typeof(value) == 'function') {
        let original = value;
        ReallyLongNonClashingName[name] = function(/* *args */) {
            return original.apply(ReallyLongNonClashingName, arguments);
        };
    }
}

and now both something.addEventListener('onclick', ReallyLongNonClashingName.onClick, false) and something.removeEventListener('onClick', ReallyLongNonClashingName.onClick, false) work (and you can use this.onclick instead if it's another member doing the (un)registering). The way this uses let is basically the same as the other example (the one with the alert(i) handlers), so perhaps there is a better place to put this, just not sure where. Feel free to copy over to a code snippets page or something if it's not appropriate here :). Marienz 09:57, 27 August 2007 (PDT)

FWIW, a more common solution is passing anonymous function wrappers as the event handlers, i.e. smth.onclick = function(e) { return MyObject.onClick(e); }. --Nickolay 22:28, 8 September 2007 (PDT)

What does "completion value" mean?

Hello. I am a Japanese MDC user, and now I'm translating this article into Japanese ({{mediawiki.interwiki('ja', 'New_in_JavaScript_1.7', 'ja:New in JavaScript 1.7')}}). But I don't understand the meaning of the sentence "The completion value of the let statement is the completion value of the block." in New in JavaScript 1.7#let statement. What does "completion value" mean? --Yuichirou 07:01, 20 September 2007 (PDT)

Sheppy says this was copied from the text in specification and neither he nor me know what this is supposed to mean. I suggest removing this text from the article and asking for clarification in dev-tech-js-engine. --Nickolay 08:06, 24 September 2007 (PDT)
Oh, really... I'd like to ask, but considering my English, it's too hard for me. If possible, I'd like you or other English speakers to do so and rewrite this article. It's good for other language MDC users, not only me. --Yuichirou 19:48, 24 September 2007 (PDT)

JS 1.7 in XBL?

How does one enable JS 1.7 in XBL? Doesn't seem to work. I've used the proper attribute for script, but doesn't seem to work in XBL. Niczar 05:36, 24 September 2007 (PDT)

I think you can't. Could you ask in dev-tech-xbl (mozilla.dev.tech.xbl) and check for / file a bug if you don't get a response? --Nickolay 08:13, 24 September 2007 (PDT)

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. <a href="User:Marienz">Marienz</a> 09:31, 27 August 2007 (PDT)
</p>
<dl><dd> Yep, this could be mentioned. --<a href="User:Nickolay">Nickolay</a> 22:28, 8 September 2007 (PDT)
</dd></dl>
<h3 name="Another_let_.28and_destructuring_assignment.29_example"> Another <code>let</code> (and destructuring assignment) example </h3>
<p>I agree with the <a href="en/JavaScript_style_guide">JavaScript_style_guide</a> that it is useful to "wrap functions and variables inside an object with a unique name to avoid conflicting with existing or future function and variable names", but having to refer to the name of that wrapper object all over the place is annoying (since it should have a nontrivial name to be of use for preventing collisions). It helps if you can refer to <code>this</code> instead of the full name, but that does not work from event handlers unless you do something like:
</p>
<pre>// This is not real-world code, obviously :P
var ReallyLongNonClashingName = {
    data: 1,

    onClick: function(evt) {
        alert(this.data);
    }
};

// but this is (except for the ReallyLongNonClashingName)
for (let [name, value] in ReallyLongNonClashingName) {
    if (typeof(value) == 'function') {
        let original = value;
        ReallyLongNonClashingName[name] = function(/* *args */) {
            return original.apply(ReallyLongNonClashingName, arguments);
        };
    }
}
</pre>
<p>and now both <code>something.addEventListener('onclick', ReallyLongNonClashingName.onClick, false)</code> and <code>something.removeEventListener('onClick', ReallyLongNonClashingName.onClick, false)</code> work (and you can use <code>this.onclick</code> instead if it's another member doing the (un)registering). The way this uses <code>let</code> is basically the same as the other example (the one with the <code>alert(i)</code> handlers), so perhaps there is a better place to put this, just not sure where. Feel free to copy over to a code snippets page or something if it's not appropriate here :). <a href="User:Marienz">Marienz</a> 09:57, 27 August 2007 (PDT)
</p>
<dl><dd> FWIW, a more common solution is passing anonymous function wrappers as the event handlers, i.e. smth.onclick = function(e) { return MyObject.onClick(e); }. --<a href="User:Nickolay">Nickolay</a> 22:28, 8 September 2007 (PDT)
</dd></dl>
<h3 name="What_does_.22completion_value.22_mean.3F"> What does "completion value" mean? </h3>
<p>Hello. I am a Japanese MDC user, and now I'm translating this article into Japanese ({{mediawiki.interwiki('ja', 'New_in_JavaScript_1.7', 'ja:New in JavaScript 1.7')}}). But I don't understand the meaning of the sentence "<i>The completion value of the let statement is the completion value of the block.</i>"  in <a href="en/New_in_JavaScript_1.7#let_statement">New in JavaScript 1.7#let statement</a>. What does "<i>completion value</i>" mean? --<a href="User:Yuichirou">Yuichirou</a> 07:01, 20 September 2007 (PDT)
</p>
<dl><dd> Sheppy says this was copied from the text in specification and neither he nor me know what this is supposed to mean. I suggest removing this text from the article and asking for clarification in dev-tech-js-engine. --<a href="User:Nickolay">Nickolay</a> 08:06, 24 September 2007 (PDT)
<dl><dd> Oh, really... I'd like to ask, but considering my English, it's too hard for me. If possible, I'd like you or other English speakers to do so and rewrite this article. It's good for other language MDC users, not only me. --<a href="User:Yuichirou">Yuichirou</a> 19:48, 24 September 2007 (PDT)
</dd></dl>
</dd></dl>
<h3 name="JS_1.7_in_XBL.3F"> JS 1.7 in XBL? </h3>
<p>How does one enable JS 1.7 in XBL? Doesn't seem to work. I've used the proper attribute for script, but doesn't seem to work in XBL. <a href="User:Niczar">Niczar</a> 05:36, 24 September 2007 (PDT)
</p>
<dl><dd> I think you can't. Could you ask in dev-tech-xbl (mozilla.dev.tech.xbl) and check for / file a bug if you don't get a response? --<a href="User:Nickolay">Nickolay</a> 08:13, 24 September 2007 (PDT)
</dd></dl>
Revert to this revision