Iterator/Generator methods and Iterator Generics

# TOYAMA Nao (19 years ago)

JS1.7 introduced iterators/generators from Python, but it misses itertools functions [1]. I suggest ES4 supports these functions as methods of iterators/generators and generic methods so that they can be applied to custom generators. For example, an implementation of Python's ifilter in JS1.7 can be like:

var GeneratorPrototype = (function () { yield; })().proto; Iterator.prototype.filter = GeneratorPrototype.filter = function (callback, thisObject) { for (var i in this) if (callback.call(thisObject, i, this)) yield i; }; Iterator.filter = function (iter, callback, thisObject) { return Iterator.prototype.filter.call(iter, callback, thisObject); };

Of course "Iterator" in above code will be "Enumerator" in ES4 as per the iterators and generators proposal [2].

[1] docs.python.org/lib/itertools-functions.html [2] developer.mozilla.org/es4/proposals/iterators_and_generators.html#enumeration

# nanto_vi (19 years ago)

Sorry, I mistook my e-mail account.

# Brendan Eich (19 years ago)

On Jan 29, 2007, at 2:58 PM, TOYAMA Nao wrote:

JS1.7 introduced iterators/generators from Python, but it misses itertools functions [1]. I suggest ES4 supports these functions as methods of iterators/generators and generic methods so that they
can be applied to custom generators. For example, an implementation of Python's ifilter in JS1.7 can be like:

var GeneratorPrototype = (function () { yield; })().proto; Iterator.prototype.filter = GeneratorPrototype.filter = function (callback, thisObject) { for (var i in this) if (callback.call(thisObject, i, this)) yield i; };

I was just working on this part of the proposal.

In theory it is easy to add standard library methods to the spec at
this point if they can be expressed entirely in the new language. In
practice we are saying "no new features", especially to features that
refract through the type system and runtime semantics.

However, I think the ML- and Haskell-inspired itertools from Python
have no such effects, and should be considered for inclusion in the
standard library specified by ES4, so we don't have to re-standardize
them later after shipping them in Firefox N+1 without a spec ;-).

But I do not believe they should be fixed or prototype methods of
nominal types (classes). Rather, they should simply be generic
functions in the iterator namespace, (e.g. iterator::zip or use
namespace iterator; ... zip(...)).

With Array and String, ES1-3 stipulated generic prototype methods,
making for awkwardness when applying to other kinds of objects. For
ES4, as in JS1.6+, we are reflecting these as static generic methods
on their classes, simply using the classes as namespaces. With the
iterator namespace, we can do better and simply write functions.
That's what zip, etc., are -- they are not methods.

Thanks for your timely mail. Comments welcome.

# Yuh-Ruey Chen (19 years ago)

Well, you can add reimplement all the JS1.6 array extras (filter, etc.) on Object.prototype meaningfully (except maybe map). That would make the "intentionally generic" methods truly be generic in practice.

The downside would be the problem that all methods share: they must be called on some non-null value. Taking the global function approach avoids this problem - in fact, I suspect that is why Python chose this approach. However, syntactically the method approach looks better, e.g. array.length reads better than len(array) IMO.

-Yuh-Ruey Chen

# Yuh-Ruey Chen (19 years ago)

Brendan Eich wrote:

But I do not believe they should be fixed or prototype methods of
nominal types (classes). Rather, they should simply be generic
functions in the iterator namespace, (e.g. iterator::zip or use
namespace iterator; ... zip(...)).

With Array and String, ES1-3 stipulated generic prototype methods,
making for awkwardness when applying to other kinds of objects. For
ES4, as in JS1.6+, we are reflecting these as static generic methods
on their classes, simply using the classes as namespaces. With the
iterator namespace, we can do better and simply write functions.
That's what zip, etc., are -- they are not methods

I was thinking about this some more. I'm not sure it's such a good idea to put such iterator functions in the iterator namespace. |use namespace iterator| would make the global iterator functions accessible without qualifiers, but also make a public::get property unaccessible if iterator::get was defined, so if I do obj.get, I can't tell whether I'm getting public::get or iterator::get unless I manually test obj.iterator::get, which kinda defeats the purpose of |use namespace iterator|.

It would be nice if there was a convenient way to bind each iterator function x to the public namespace in global scope, without having to use |use namespace iterator| (to avoid the aforementioned problem) or manually binding each such function x.

Furthermore, it seems inconsistent that the static versions of map, every, replace, etc. is placed on the built-in classes/constructors (at least in JS1.6+), e.g. String.replace, while the iterator functions get placed in another namespace. The iterator functions could be static methods of the Iterator class to be consistent. Or would all these static functions be moved to other namespaces?

Since we have packages, why not place static functions in them instead of namespaces or classes? itertools.ifilter instead of iterator::ifilter. Then we could use the import statement to bind itertools.ifilter to global.ifilter. It would be nice if iterator or Iterator could be used as the package name, but that would result in a name conflict with the iterator namespace, wouldn't it?

# Brendan Eich (19 years ago)

On Feb 5, 2007, at 11:13 PM, Yuh-Ruey Chen wrote:

Brendan Eich wrote:

But I do not believe they should be fixed or prototype methods of nominal types (classes). Rather, they should simply be generic functions in the iterator namespace, (e.g. iterator::zip or use namespace iterator; ... zip(...)).

With Array and String, ES1-3 stipulated generic prototype methods, making for awkwardness when applying to other kinds of objects. For ES4, as in JS1.6+, we are reflecting these as static generic methods on their classes, simply using the classes as namespaces. With the iterator namespace, we can do better and simply write functions. That's what zip, etc., are -- they are not methods

I was thinking about this some more. I'm not sure it's such a good
idea to put such iterator functions in the iterator namespace. |use
namespace iterator| would make the global iterator functions accessible without qualifiers, but also make a public::get property unaccessible if iterator::get was defined

No, you could always say what you mean: obj.public::get.

, so if I do obj.get, I can't tell whether I'm getting public::get or iterator::get unless I manually test obj.iterator::get, which kinda defeats the purpose of |use namespace iterator|.

Namespaces are like that. If you don't want implicit qualification,
don't use namespace foo.

It would be nice if there was a convenient way to bind each iterator function x to the public namespace in global scope, without having to use |use namespace iterator| (to avoid the aforementioned problem) or manually binding each such function x.

This is an argument for putting itertools-like functions in a package
or namespace other than iterator. Which I see you propose below :-).

Furthermore, it seems inconsistent that the static versions of map, every, replace, etc. is placed on the built-in classes/constructors
(at least in JS1.6+), e.g. String.replace, while the iterator functions
get placed in another namespace. The iterator functions could be static methods of the Iterator class to be consistent. Or would all these static functions be moved to other namespaces?

Having an Iterator class is problematic. I'm revising the wiki now
and I'm not done yet, but one goal is to avoid telegraphing that
there is some nominal-type-system protocol behind iteration, and to
participate you have to subclass Iterator -- or any such thing.

Since we have packages, why not place static functions in them instead of namespaces or classes? itertools.ifilter instead of iterator::ifilter. Then we could use the import statement to bind itertools.ifilter to global.ifilter.

This is the right way to go, especially if the Python itertools are
ported under their names (but they want to drag in slice, map, and
other Python generic functions). Still the right way to go, modulo
that parenthetical concern.

It would be nice if iterator or Iterator could be used as the package name, but that would result in a name conflict with the iterator namespace, wouldn't it?

iterator is the namespace name, a global constant binding. It seems
from our spidering not to be taken (prototype.js uses iterator for
local var names, no problem). Package names are a matter not
addressed by ES4, but the obvious reversed FQDN prefixing seems
likely. The Flex SDK does something like this, but IIRC the first
component is "mx" (not com.macromedia or com.adobe ;-).

In any event, package names for standard library packages need to be
sorted out for ES4, IMHO, but we haven't done it yet.