tc39 / ecma262

Status, process, and documents for ECMA-262
https://tc39.es/ecma262/
Other
15.05k stars 1.28k forks source link

Generator.prototype is not defined #3230

Open arai-a opened 11 months ago

arai-a commented 11 months ago

The "Generator Objects" section first mentions "A Generator is an instance of a generator function ...".

https://tc39.es/ecma262/#sec-generator-objects

A Generator is an instance of a generator function and conforms to both the Iterator and Iterable interfaces.

Then "Properties of the Generator Prototype Object" section defines "Generator prototype object" as %GeneratorFunction.prototype.prototype%

https://tc39.es/ecma262/#sec-properties-of-generator-prototype

The Generator prototype object:

  • is %GeneratorFunction.prototype.prototype%.

The "Generator prototype object" name is used by GeneratorFunction.prototype.prototype's definition, which makes sense:

https://tc39.es/ecma262/#sec-generatorfunction.prototype.prototype

The initial value of GeneratorFunction.prototype.prototype is the Generator prototype object.

But remaining subsections of "Generator Objects" define properties of Generator.prototype, that sounds like the same thing as %GeneratorFunction.prototype.prototype%, but it's not defined explicitly:

https://tc39.es/ecma262/#sec-generator.prototype.constructor

27.5.1.1 Generator.prototype.constructor

https://tc39.es/ecma262/#sec-generator.prototype.next

27.5.1.2 Generator.prototype.next ( value )

It also makes the first paragraph "A Generator is an instance of ..." confusing, that it sounds like Generator in Generator.prototype.constructor is "A Generator" instance (which is not true, because the instance doesn't have prototype property).

There would be 2 options to solve this:

Same for AsyncGenerator.prototype in https://tc39.es/ecma262/#sec-asyncgenerator-objects

arai-a commented 11 months ago
* (A) Replace all occurrences of `Generator.prototype` with `%GeneratorFunction.prototype.prototype%` (while keeping the ids of those sections, to avoid breaking links)

This doesn't work with the current ecmarkup, because it doesn't accept a dot inside %.

https://github.com/tc39/ecmarkup/blob/08aa4a70f7695509fa779acf9173862a96de4084/src/lint/collect-header-diagnostics.ts#L50-L56

I'll see if the linter can be modified to accept the syntax.

ljharb commented 11 months ago

"Generator" is defined in the first sentence of https://tc39.es/ecma262/#sec-generator-objects, which means that "Generator.prototype.constructor", for example, is also defined. I'm confused what the problem is here.

arai-a commented 11 months ago

I was assuming that "Generator" means the g() value for function *g() {}. Isn't it correct? Does it mean the g value ?

ljharb commented 11 months ago

A Generator is an instance of a generator function and conforms to both the Iterator and Iterable interfaces.

I read that as the return value of g(), there, yes.

arai-a commented 11 months ago

In that case, Generator.prototype is undefined, given g().prototype is undefined.

ljharb commented 11 months ago

ahh ok, on a reread "instance of a generator function" actually means g itself, yes. I see how that's confusing as I was myself confused.

It's still defined, though :-)

arai-a commented 11 months ago

The sentence says "A Generator" conforms to the Iterator interfaces and Iterable Interfaces. g() conforms to both, but g doesn't conform to neither. So, only g() matches the requirement.

https://tc39.es/ecma262/#sec-generator-objects

A Generator is an instance of a generator function and conforms to both the Iterator and Iterable interfaces.

https://tc39.es/ecma262/#sec-iterable-interface

The Iterable Interface The Iterable interface includes the property described in Table 77: ... @@iterator

https://tc39.es/ecma262/#sec-iterator-interface

The Iterator Interface An object that implements the Iterator interface must include the property in Table 78. Such objects may also implement the properties in Table 79. ... "next" "return" "throw"

To my understanding, g is "a generator function", and "instance of" there means the function call operation, thus "instance of a generator function" there should be g().

Actually, "SOMETHING instance"/"instance of SOMETHING" term seems to be used in 2 ways throughout the spec, one is that SOMETHING itself, and the other is that the result of SOMETHING(), that would be the source of the confusion here.

ljharb commented 11 months ago

I agree with you that some terminology needs clarifying in this section.

arai-a commented 11 months ago

I've checked the occurrences of "generator(s)" (without explicit suffix like "generator function" or "GeneratorBody"), and almost all cases "generator" means g().

Sometimes "Generator" is used as abbreviation of "GeneratorFunction", but still the formal name would be "GeneratorFunction" for them.

https://tc39.es/ecma262/#sec-strict-mode-code

Function code that is supplied as the arguments to the built-in Function, Generator, AsyncFunction, and AsyncGenerator constructors is...

One exception is the following, which I'm not sure if it's really intended to be abbreviation:

https://tc39.es/ecma262/#table-well-known-intrinsic-objects

| %GeneratorFunction% | The constructor of Generators |

But anyway, defining "Generator" as a name of g() sounds more cleaner. and in that case, the Generator.prototype notation remains problematic.

Then, if replacing with %GeneratorFunction.prototype.prototype% is not good for readability, what if we add yet another well-known intrinsic %GeneratorPrototype%, in the same way as %StringIteratorPrototype%? That way the https://github.com/tc39/ecmarkup/pull/564 patch isn't necessary.

I haven't chosen this in the first place because I thought the dot in the %GeneratorFunction.prototype.prototype% is part of name, instead of actual property operation, and having another alias would make the situation complicated. But if %GeneratorFunction.prototype.prototype% means almost same thing as %GeneratorFunction%.prototype.prototype, adding yet another well-known intrinsic for the value would be fine?

Also, about the "instance of a generator function", I think we should avoid the use of the combination of "instance"+"generator function" there, because both "GeneratorFunction constructor" and function* g() {} are callable, and it's hard to see which it means, given "instance" means 2 things. We could instead say "A Generator can be created by calling a generator function. A generator conforms to both the Iterator and Iterable interfaces."