On Dec 10, 2009, at 11:31 AM, Mike Samuel wrote:

I was assuming iterators would work without clients explicitly
trapping STOP_ITERATION, which is what proxies would provide.   But I
suppose if we're doing proxies, we can also do the syntactic sugar to
do away with that in new looping constructs.

We do indeed have for-in loops, comprehensions, and generator expressions all automatically catching StopIteration in SpiderMonkey and Rhino. There is hardly ever a reason to write a try/catch -- just as in Python.


Proxy based iterators work well with existing loop constructs though
   while ('next' in iterator) doSomething(iterator.next);

There are lots of convenient ways to express iteration, but one that mandates proxies is inherently heavier and harder to optimize than I think we (implementors or in some cases users) want.


This works because I used a different definition of iterator.  In my
example, the producer has almost exactly the same contract as the next
method of your iterator, differing only in the value thrown, and the
proxy served to convert it to an iterator.
The iterator then an object such that
  - there is no next property iff the iterator is exhausted !('next'
in iterator)
  - the next value in the series can be retrieved by reading the next
property which advances the iterator
  - optionally, setting or deleting the next property mutates the
last element returned on the underlying collection

The last element, or the next element?

Proxies can propagate effects to other objects, for sure, but this is not only expensive, it's also hard to analyze. An iteration protocol should be more functional (pure).

We chose to borrow from Python first in the spirit of programming language design by borrowing from older languages, second to reuse developer brainprint.

But the functional (with light OO dusting on top, which could be removed as noted -- getting rid of |this|) flavor of the iteration protocol in SpiderMonkey and Rhino JS1.7+ is winning both for implementors and users, in our experience.

To criticize our JS1.7/1.8 experience a bit:

A. The obvious problem is that we hang the meta-level handler off the base-level object, as Python does with its __iter__. But Object.defineIterator seems like the fix for this bug.

B. Creating an object with a next method instead of a closure may be one object too many. The object need not carry any state that's not in the next method's environment (as in the examples I showed).

But the object does provide an identity separate from next, in which send, throw, and close methods are bound for generators. And the object allows state representation optimizations other than closure- based ones.

C. Generators, being flat (one frame of activation saved) yet heap- escaping, don't always compose nicely. This has spawned PEP 380 (http://www.python.org/dev/peps/pep-0380/ ).

Generators are nevertheless quite convenient according to reports from our users, and pretty easy to implement in any implementation that compiles into bytecode or something more sophisticated, instead of walking ASTs to evaluate code.

It's important not to oversell generators as solving concurrency issues or being "coroutines" -- they are best thought of as the simplest way to write an iteration protocol handler (or more casually, "an iterator"). Here are the example iterators recast as generators:

function keyIterator() {
    let keys = Object.keys(this);
    for (let i = 0; i < keys.length; i++)
        yield keys[i];
}

function indexIterator() {
    for (let i = 0; i < this.length; i++)
        yield i;
}

When called, a generator returns an iterator, so these are factories. The functional version had to return objects with next methods:

function keyIterator() {
    let keys = Object.keys(this);
    let i = 0;
    return {
        next: function () {
            if (i == keys.length)
                throw StopIteration;
            return keys[i++];
        }
    };
}

function indexIterator() {
    let self = this;
    let i = 0;
    return {
        next: function () {
            if (i == self.length)
                throw StopIteration;
            return i++;
        }
    };
}

This use-case is where generators shine.

/be
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to