Code smell? Iterator prototype has iterator method that returns "this"

# John Lenz (8 years ago)

This seems ripe for misuse: you don't want two "owners" for the same iterator calling "next" and normally, without the Iterator interface implementation, you would expect "iterator()" to always return an instance of the iterator that the caller "owned".

Can anyone provide any historical context on why this method was added to the "iterator"?

# Boris Zbarsky (8 years ago)

On 7/25/16 11:19 AM, John Lenz wrote:

Can anyone provide any historical context on why this method was added to the "iterator"?

The idea is that you can do this:

for (var something of myarray.entries())

and similar for other iterator-returning methods. The way for-of works is that it will try to call iterator() on the thing to the right of the "of", which in this case is an Iterator instance.

# John Lenz (8 years ago)

I understand the way it is used, but I don't understand why. "for-of" could have been spec'd to take either an Iterable (an object with an [Symbol.iterator] method) or an Iterator. Or just an Iterable.

# Tab Atkins Jr. (8 years ago)

On Mon, Jul 25, 2016 at 4:28 PM, John Lenz <concavelenz at gmail.com> wrote:

I understand the way it is used, but I don't understand why. "for-of" could have been spec'd to take either an Iterable (an object with an [Symbol.iterator] method) or an Iterator. Or just an Iterable.

Not just for-of, but the whole rest of the world (in particular, anything that directly consumes iterables) would also have to make that distinction. Much easier to just let everyone pretend that an iterator is iterable, so you can use a common API between the two types. (Also, Python already worked this way, and a lot of JS iterator details were copied from Python originally.)

# John Lenz (8 years ago)

Yes, but at the cost of being able to reason / declare what kind of object is actually required. But, I'm sure there is nothing that can be changed here.

# Allen Wirfs-Brock (8 years ago)

On Jul 25, 2016, at 4:38 PM, John Lenz <concavelenz at gmail.com> wrote:

Yes, but at the cost of being able to reason / declare what kind of object is actually required. But, I'm sure there is nothing that can be changed here.

The kind of object that is required is one that implements the Iterable interface (i.e., has a Symbol.interable method that returns an object that implements the Iterator interface). What is unclear about that?

# Andreas Rossberg (8 years ago)

The ES6 iterator/iterable story has been criticised more than once, by a number of people. Too lazy to dig up all those threads, but if you search es-discuss for iterable and iterator you will find it a reoccurring scheme. AFAIK, this thread contained the first such discussion: esdiscuss/2013-March/029004

The short story from my POV is: the notion of iterators vs. iterables in ES6 makes no coherent sense, but many people want their implicit conversions despite any smell, and this basically provides (a user-definable) one from anything to an iterator.

# Michael Theriot (8 years ago)

There are many things I still don't understand about iterators...

var iter = [].values();
iter[Symbol.iterator]() === iter;

var weirdFunction = iter[Symbol.iterator];
weirdFunction.call(iter) === iter;

var weirdInstance = new weirdFunction(); // what is this??
# Jordan Harband (8 years ago)

new weirdFunction() would === iter because a constructor that returns an object (this), returns that object when newed - which is how functions have worked since ES3 (or probably ES1).

# Claude Pache (8 years ago)

Le 27 juil. 2016 à 06:31, Michael Theriot <michael.lee.theriot at gmail.com> a écrit :

There are many things I still don't understand about iterators...

var iter = [].values();
iter[Symbol.iterator]() === iter;

var weirdFunction = iter[Symbol.iterator];
weirdFunction.call(iter) === iter;

var weirdInstance = new weirdFunction(); // what is this??

My intuition says: "TypeError: weirdFunction is not a constructor".

# Claude Pache (8 years ago)

Le 27 juil. 2016 à 07:16, Jordan Harband <ljharb at gmail.com> a écrit :

new weirdFunction() would === iter because a constructor that returns an object (this), returns that object when newed - which is how functions have worked since ES3 (or probably ES1).

If weirdFunction were defined as if by evaluating function () { return this }, yes. But in general, functions are not necessarily constructors (just try new Math.sin in your favourite JS environment).

# Claude Pache (8 years ago)

Le 27 juil. 2016 à 08:56, Claude Pache <claude.pache at gmail.com> a écrit :

Le 27 juil. 2016 à 07:16, Jordan Harband <ljharb at gmail.com> a écrit :

new weirdFunction() would === iter because a constructor that returns an object (this), returns that object when newed - which is how functions have worked since ES3 (or probably ES1).

If weirdFunction were defined as if by evaluating function () { return this }, yes. But in general, functions are not necessarily constructors (just try new Math.sin in your favourite JS environment).

—Claude

Correction: If weirdFunction were defined as if by evaluating function () { return this }, no: in such a constructor (more precisely: when such a function is used as a constructor), this is a brand-new "instance"; it can’t be === to a previously existing object such as iter.

(Given how confusing and useless it is, I hope that my intuition ("not a constructor") is correct.)

# Raul-Sebastian Mihăilă (8 years ago)

Indeed, according to www.ecma-international.org/ecma-262/7.0/index.html#sec-functionallocate, generators don't have the [[Construct]] internal method.

# Allen Wirfs-Brock (8 years ago)

On Jul 26, 2016, at 11:52 PM, Claude Pache <claude.pache at gmail.com> wrote:

var weirdInstance = new weirdFunction(); // what is this??

My intuition says: "TypeError: weirdFunction is not a constructor”.

exactly, because weirdFunction is actually tc39.github.io/ecma262/#sec-%iteratorprototype%-@@iterator, tc39.github.io/ecma262/#sec-%iteratorprototype%-@@iterator which is a built-in function that is not identified as a constructor.

tc39.github.io/ecma262/#sec-ecmascript-standard-built-in-objects, tc39.github.io/ecma262/#sec-ecmascript-standard-built-in-objects says: "Built-in function objects that are not identified [in this specification] as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function.”

Step 7 of tc39.github.io/ecma262/#sec-evaluatenew, tc39.github.io/ecma262/#sec-evaluatenew says: If IsConstructor(constructor) is false, throw a TypeError exception.

# Michael Theriot (8 years ago)

At least in Chrome, new weirdFunction() !== iter nor does it throw a TypeError... but maybe that's a bug...

# Caitlin Potter (8 years ago)

That bug was filed today/yesterday and fixed, thanks to this thread :)