instantiating generators
This is not what we prototyped and shipped in SpiderMonkey starting in 2006, and Rhino and probably other engines cloned, for years. That's not to say we should or shouldn't do it, but I'm always leery of made-up stuff without any prototype-implementation mileage.
Allen, is there any reason to make things more nested, with hidden (Generator) constructor? I see what you're getting at but the lack of it has never been an issue for JS1.7+ users. When in doubt, flat is better than nested (Zen of Python).
We discussed the factoring of the generator "object model" at the Nov 27 meeting. In the notes rwldrn/tc39-notes/blob/master/es6/2012-11/nov-27.md there is a sketch of the hierarchy we agreed to: dl.dropbox.com/u/3531958/tc39/generator-diagram-1.jpg
The design Andy referenced is one I presented at the meeting. It is very close to but not identical to the that sketched in the above linked whiteboard diagram.
But most JS developers won't need to think about this at all. They just defined generator constructors using generator expressions or function* declarations and then either implicitly (generator expressions) or explicitly call them to get generator instance. However, there are edge cases and consistency issues where the actual object model becomes visible and is need to explain the most reasonable behavior. For example consider:
function *Interval(start, end) { for (;start<=end;start++) yield start; }
let i1 = Interval(1,10); let i2 = Interval(20,10);
It seems most consistent with JavaScript conventions that: console.log(i1 instanceof Interval); //true console.log(i1.constructor === i2.constructor); //true console.log(i2.constructor === Interval); //true console.log(Object.getPrototypeOf(i2) === i2.constructor.prototype);
Also i1 and i2 essentially share common implementations of the next,send,throw,close methods that are derived from the body of the Interval generator definition. It makes sense for all instances of Interval to share those methods rather than replicating them as own methods. This suggests that they belong in a common prototype object.
At the Nov meeting we discussed all these things (and others) and there was fairly strong consensus that this sort of design was needed for provide a plausible meta foundation for explaining and understanding how generators fit with the rest of ES. That basically matched my personal experience. I originally created various forms (I think I showed 4 alternatives at the meeting) of that "class hierarchy" diagram to understand what function *(){} was actually doing so I could spec. it adequately. Once I had the full abstraction worked out in this manner. everything became quite clear.
I acknowledge that SpiderMonkey has had generators without worrying about such details. To me that simply reflects the difference between the expectations for an initial feature-functionality focused implementation and what we need to do as part of a standard. Spider Monkey could get away with a more ad hoc design that didn't worry too much about edge cases but as part of a standard that is going to have multiple implementations and needs to support future language evolution it is important that we work through these details and to try to "get it right".
Regarding new Interval(1,10). People don't need to say that (although I don't think there is anything wrong with thinking about it that way) and if we want to we can make it illegal. However, I think it is extra design/spec/implementation work to disallow it and it seems like an arbitrary restriction.
My intent for the near future is to take the consensus whiteboard design from the Nov. 27 meeting and use it as the basis for what goes into the next ES6 draft.
I would prefer having to use new
(but don’t have strong feelings about it): generators are more like constructors than like functions. When I first started experimenting with them in Firefox, it took me a while to figure that out (even though it is obvious in hindsight). With new
, I’d probably have figured it out quicker.
Axel
On Mar 15, 2013, at 11:22 AM, Axel Rauschmayer wrote:
I would prefer having to use
new
(but don’t have strong feelings about it): generators are more like constructors than like functions. When I first started experimenting with them in Firefox, it took me a while to figure that out (even though it is obvious in hindsight). Withnew
, I’d probably have figured it out quicker.
My experience was similar.
On 3/15/2013 11:51 AM, Allen Wirfs-Brock wrote:
On Mar 15, 2013, at 11:22 AM, Axel Rauschmayer wrote:
I would prefer having to use
new
(but don't have strong feelings about it): generators are more like constructors than like functions. When I first started experimenting with them in Firefox, it took me a while to figure that out (even though it is obvious in hindsight). Withnew
, I'd probably have figured it out quicker.My experience was similar.
Mine was as well. Admittedly it's kind of odd to use something like new obj.method
but it does more accurately describe what it was going on.
Ah, methods are more tricky! Then you have this
to contend with.
Yeah but since the generator holds the initial |this| for its lifetime you can treat it kind of like a bound function.
On Fri, Mar 15, 2013 at 11:51 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
On Mar 15, 2013, at 11:22 AM, Axel Rauschmayer wrote:
I would prefer having to use
new
(but don’t have strong feelings about it): generators are more like constructors than like functions. When I first started experimenting with them in Firefox, it took me a while to figure that out (even though it is obvious in hindsight). Withnew
, I’d probably have figured it out quicker.My experience was similar.
Mine's the opposite - my experience with generators in Python built up a strong and very natural-feeling intuition that a generator was just a function that returned a "magic list". Trying to push that into a constructor notion would feel awkward.
Actually using it would be even more awkward than thinking about it, I believe. For example, I use the enumerate() generator all the time in Python. Having to always write:
for(x of new enumerate(seq)) {...}
would feel really weird, even if you changed the conjugation of the function to "enumeration()".
On Mar 15, 2013, at 1:18 PM, Tab Atkins Jr. wrote:
On Fri, Mar 15, 2013 at 11:51 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
On Mar 15, 2013, at 11:22 AM, Axel Rauschmayer wrote:
I would prefer having to use
new
(but don’t have strong feelings about it): generators are more like constructors than like functions. When I first started experimenting with them in Firefox, it took me a while to figure that out (even though it is obvious in hindsight). Withnew
, I’d probably have figured it out quicker.My experience was similar.
Mine's the opposite - my experience with generators in Python built up a strong and very natural-feeling intuition that a generator was just a function that returned a "magic list". Trying to push that into a constructor notion would feel awkward.
Actually using it would be even more awkward than thinking about it, I believe. For example, I use the enumerate() generator all the time in Python. Having to always write:
for(x of new enumerate(seq)) {...}
would feel really weird, even if you changed the conjugation of the function to "enumeration()".
Agree that requiring new would be ackward. But permitting it seems reasonable.
for what is worth it, agreed with Tab Atkins here ... new
does not
improve much semantically speaking, it's actually just confusing, IMHO
On Fri, Mar 15, 2013 at 1:22 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
Agree that requiring new would be ackward. But permitting it seems reasonable.
Yeah, I see no value in making new invalid.
Tab Atkins Jr. wrote:
On Fri, Mar 15, 2013 at 11:51 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
On Mar 15, 2013, at 11:22 AM, Axel Rauschmayer wrote:
I would prefer having to use
new
(but don’t have strong feelings about it): generators are more like constructors than like functions. When I first started experimenting with them in Firefox, it took me a while to figure that out (even though it is obvious in hindsight). Withnew
, I’d probably have figured it out quicker. My experience was similar.Mine's the opposite - my experience with generators in Python built up a strong and very natural-feeling intuition that a generator was just a function that returned a "magic list". Trying to push that into a constructor notion would feel awkward.
Actually using it would be even more awkward than thinking about it, I believe. For example, I use the enumerate() generator all the time in Python. Having to always write:
for(x of new enumerate(seq)) {...}
would feel really weird, even if you changed the conjugation of the function to "enumeration()".
Don't worry, we are not going to require 'new'.
but then the direction is a bit inconsistent since native constructors are going to require `new
(sorry, I sent by accident) I meant native requires new
and there is
already a subset, generators, that are flexible as native constructors are
now (e.g. Object() instead of new Object())
anyway, better than "mandatory new
" so ...
I don't know what you meant below in the first paragraph, but I'm going to assume you agree that 'new' should not be required for generators. :-|.
On Fri, Mar 15, 2013 at 11:22 AM, Axel Rauschmayer <axel at rauschma.de> wrote:
I would prefer having to use
new
(but don’t have strong feelings about it): generators are more like constructors than like functions. When I first started experimenting with them in Firefox, it took me a while to figure that out (even though it is obvious in hindsight). Withnew
, I’d probably have figured it out quicker.
I agree with Tab: I wonder if your mental model for generators might not continue to evolve.
I would hate to have to write: for (k of new tree.preorder()) rather than: for (k of tree.preorder())
I agree on that and on top I would rather throw if new
is used ... but I
understand on being permissive, is just weird Object()
instead of new Object()
won't be accepted anymore, but for generators there is such
exception. This is all I was trying to say.
On Fri, Mar 15, 2013 at 11:22 AM, Axel Rauschmayer <axel at rauschma.de> wrote: I would prefer having to use
new
(but don’t have strong feelings about it): generators are more like constructors than like functions. When I first started experimenting with them in Firefox, it took me a while to figure that out (even though it is obvious in hindsight). Withnew
, I’d probably have figured it out quicker.I agree with Tab: I wonder if your mental model for generators might not continue to evolve.
I would hate to have to write: for (k of new tree.preorder()) rather than: for (k of tree.preorder())
Yes, it will probably evolve. The wish for new
comes up if you know what’s inside a generator function and are surprised that you need to invoke a method to start executing the function body. If you treat it as a black box then new
makes less sense, then it is roughly a function or method that returns an iterator.
(Tongue in cheek, you could argue that Python does treat generators like classes)
Andrea Giammarchi wrote:
I agree on that and on top I would rather throw if
new
is used ...
That might be ok. The newborn passed in as this could be returned via first yield, though, so while it's an odd thing to take advantage of, the semantics of new and function* combine without harm.
Given "function* g() { yield 1; }", are these equivalent?
new g(); g();
Somehow I had assumed that /calling/ would be the normal way to instantiate a generator, but I see "new" in meetings:proposed_generator_class_hierarcy_nov_2013.png.
Thanks,
Andy