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

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

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

John Lenz-4
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"?

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Boris Zbarsky
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.

-Boris

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

John Lenz-4
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 8:38 AM, Boris Zbarsky <[hidden email]> wrote:
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.

-Boris

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


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Tab Atkins Jr.
On Mon, Jul 25, 2016 at 4:28 PM, John Lenz <[hidden email]> 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.)

~TJ
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

John Lenz-4
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 Mon, Jul 25, 2016 at 4:31 PM, Tab Atkins Jr. <[hidden email]> wrote:
On Mon, Jul 25, 2016 at 4:28 PM, John Lenz <[hidden email]> 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.)

~TJ


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Allen Wirfs-Brock

> On Jul 25, 2016, at 4:38 PM, John Lenz <[hidden email]> 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?
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Andreas Rossberg-4
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: https://mail.mozilla.org/pipermail/es-discuss/2013-March/029004.html

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.

On 26 July 2016 at 04:16, Allen Wirfs-Brock <[hidden email]> wrote:

> On Jul 25, 2016, at 4:38 PM, John Lenz <[hidden email]> 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?
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Michael Theriot
In reply to this post by John Lenz-4
There are many things I still don't understand about iterators...

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

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

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


On Mon, Jul 25, 2016 at 10:19 AM, John Lenz <[hidden email]> wrote:
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"?

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



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Jordan Harband
`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).

On Tue, Jul 26, 2016 at 9:31 PM, Michael Theriot <[hidden email]> wrote:
There are many things I still don't understand about iterators...

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

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

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


On Mon, Jul 25, 2016 at 10:19 AM, John Lenz <[hidden email]> wrote:
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"?

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



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



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Claude Pache
In reply to this post by Michael Theriot

> Le 27 juil. 2016 à 06:31, Michael Theriot <[hidden email]> a écrit :
>
> There are many things I still don't understand about iterators...
>
> ```js
> 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

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Claude Pache
In reply to this post by Jordan Harband

> Le 27 juil. 2016 à 07:16, Jordan Harband <[hidden email]> a écrit :
>
> `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).

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

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Claude Pache

> Le 27 juil. 2016 à 08:56, Claude Pache <[hidden email]> a écrit :
>
>
>> Le 27 juil. 2016 à 07:16, Jordan Harband <[hidden email]> a écrit :
>>
>> `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).
>
> 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.)

—Claude

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Allen Wirfs-Brock
In reply to this post by Claude Pache

On Jul 26, 2016, at 11:52 PM, Claude Pache <[hidden email]> wrote:


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

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


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

 "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 https://tc39.github.io/ecma262/#sec-evaluatenew says: If IsConstructor(constructor) is false, throw a TypeError exception.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

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

On Wed, Jul 27, 2016 at 10:12 AM, Allen Wirfs-Brock <[hidden email]> wrote:

On Jul 26, 2016, at 11:52 PM, Claude Pache <[hidden email]> wrote:


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

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


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

 "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 https://tc39.github.io/ecma262/#sec-evaluatenew says: If IsConstructor(constructor) is false, throw a TypeError exception.



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

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

On Jul 27, 2016, at 7:02 PM, Michael Theriot <[hidden email]> wrote:

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

On Wed, Jul 27, 2016 at 10:12 AM, Allen Wirfs-Brock <[hidden email]> wrote:

On Jul 26, 2016, at 11:52 PM, Claude Pache <[hidden email]> wrote:


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

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


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

 "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 https://tc39.github.io/ecma262/#sec-evaluatenew says: If IsConstructor(constructor) is false, throw a TypeError exception.


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

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