Code smell? Iterator prototype has iterator method that returns "this"
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.
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.
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.)
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.
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?
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.
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??
new weirdFunction()
would === iter
because a constructor that returns
an object (this
), returns that object when new
ed - which is how
functions have worked since ES3 (or probably ES1).
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".
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 whennew
ed - 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).
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 whennew
ed - which is how functions have worked since ES3 (or probably ES1).If
weirdFunction
were defined as if by evaluatingfunction () { return this }
, yes. But in general, functions are not necessarily constructors (just trynew 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.)
Indeed, according to www.ecma-international.org/ecma-262/7.0/index.html#sec-functionallocate, generators don't have the [[Construct]] internal method.
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.
At least in Chrome, new weirdFunction() !== iter nor does it throw a TypeError... but maybe that's a bug...
That bug was filed today/yesterday and fixed, thanks to this thread :)
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"?