Check out Dart's iterators
Claude Pache
claude.pache at gmail.com
Sun Feb 10 22:32:03 PST 2013
Le 11 févr. 2013 à 03:44, Dean Landolt <dean at deanlandolt.com> a écrit :
> Has the iteration protocol been given a close look since unique symbols hit the scene? I know the iterator key was changed to a symbol (which makes great sense) but ISTM symbols offer up some design flexibility that, as far as I know, just isn't possible in any of the other languages mentioned WRT prior art.
>
> For example, the first argument to the iterator function could be a symbol that acts as a StopIteration semaphore for that iteration run. Obviously consuming an iterator with `for of` or comprehensions would implement the protocol for you (generating the symbol and testing it's identity under the covers), but it'd still be just as easy (perhaps more so) to run off an iterator run manually. If you happen know the full alphabet of the sequence you're iterator over you don't even have to use a symbol. I think it's safe to say very few sequences won't have holes, so providing nothing at all would do the Right Thing in the vast majority of cases.
>
> I know it's too late in the game for new features. Though, this is really a small tweak to the current proposal -- it's essentially the same protocol with a different signaling mechanism. There sure seem to be an awful lot of pros. It's easier to get right than the throw StopIteration dance, and I couldn't imagine a way it could be less efficient. AFAICT it's not subject to the deficiencies I've seen raised about the current spec -- no instanceof StopIteration confusion and no unnecessary catch blocks, for instance. I'm not aware of any cons.
>
So, if I understand your idea, a custom iterator would be of the following form:
myIterator = { next: function(stopIterationSemaphore) {
// instead of throw StopIteration, you should write:
return stopIterationSemaphore
}}
The idea pleased me, but I see one problem: inside a generator, the return statement may have a value, which is significant when you use delegation, since the value of the return statement of the delegated generator becomes the value of the yield* expression of the delegating generator. Now if you return just a semaphore-symbol, you have no way to transmit the value of the return statement.
In order to resolve the issue, you could use a fresh object instead of a symbol (and it will be as unique as any symbol):
myIterator = { next: function(stopIterationSemaphore) {
// instead of throw StopIteration(value), you should write:
stopIterationSemaphore.value = value
return stopIterationSemaphore
}}
and
stopIterationSemaphore = {}
result myIterator.next(stopIterationSemaphore)
if (result === stopIterationSemaphore) {
// the iteration is over.
// and the return value is stopIterationSemaphore.value
}
—Claude
>
> On Sun, Feb 10, 2013 at 9:35 PM, Claude Pache <claude.pache at gmail.com> wrote:
>
> Le 10 févr. 2013 à 22:01, David Bruant <bruant.d at gmail.com> a écrit :
>
> > <snip>
> >
> > I have to note that there is a minor security hazard in code using iterators naively:
> > import process from "m";
> >
> > var a = [1, 2, 3, 4, 5];
> > var next = 0;
> > var it = {
> > next: function(){
> > if(next < a.length){
> > // If the call to "process" throws StopIteration because it's malicious/buggy,
> > // so does this code and that's largely unexpected.
> > return process(a[next++]);
> > }
> > else{
> > throw StopIteration;
> > }
> > }
> > }
> >
> > You can always protect yourself by wrapping the call to "process" with a try/catch block.
> > <snip>
>
>
> Note that the same issue arises with generators:
>
> function* gen(a) {
> var next = 0;
> if (next < a.length) {
> // the iterator will end prematurely if "process" throws a StopIteration
> yield process(a[next++]);
> }
> }
>
> In order to mitigate the problem, instead of throwing a generic StopIteration, I think we ought to throw a specific StopIteration instance with information on which iterator has thrown. More precisely, inside a generator function, a return statement will throw a StopIteration instance with its "source" property set to the generator iterator which was terminated.
>
> For manually throwing a StopIteration from inside a "next" method of an iterator, we could use:
>
> throw new StopIteration(this)
>
> And instead of "e instanceof StopIteration", we may use a more precise check:
>
> e instanceof StopIteration && e.source === it
>
>
> —Claude
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130211/a32f4721/attachment.html>
More information about the es-discuss
mailing list