Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constructor specification is unclear #965

Closed
jorendorff opened this issue Nov 20, 2018 · 13 comments · Fixed by #1035
Closed

Constructor specification is unclear #965

jorendorff opened this issue Nov 20, 2018 · 13 comments · Fixed by #1035

Comments

@jorendorff
Copy link

Is subclassing supposed to work?

class SpamStream extends ReadableStream {
    constructor() {
        let stream;
        super({
            pull(controller) {
                controller.enqueue("spam");
                stream.spamCount++;
            }
        });
        this.spamCount = 0;
        stream = this;
    }
    hasSpammed() { return this.spamCount > 0; }
}

new SpamStream().hasSpammed()

The standard currently says:

We prefix section headings with new to indicate they are defining constructors; when doing so, we assume that NewTarget will be checked before the algorithm starts.

What it doesn't say is how this gets initialized. Mozilla's current implementation ignores NewTarget and always creates an object whose [[Prototype]] is the original value of ReadableStream.prototype. So the above code would fail; hasSpammed would not be on that object's prototype chain.

I think we want something like

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let this be ? OrdinaryCreateFromConstructor(NewTarget, the name of the per-realm intrinsic object that is this class's original prototype, the List of this class's internal slots).

(Technically, this doesn't quite work, because OrdinaryCreateFromConstructor step 1 effectively asserts that it is being called from inside ECMA-262 and not from other standards. But I think it's an improvement anyway.)

@ricea
Copy link
Collaborator

ricea commented Nov 20, 2018

I think developers would find it surprising if subclassing didn't work. My interpretation is that

This specification uses algorithm conventions very similar to those of [ECMASCRIPT], whose rules should be used to interpret it (apart from the exceptions enumerated below).

means that subclassing should work as it does for other constructors defined in ECMASCRIPT.

@domenic, is that what you intended?

@jorendorff
Copy link
Author

I figured that sentence was referring to the Algorithm Conventions section of the ECMAScript spec. Those are all notational conventions—super low-level stuff.

Higher-level patterns, like conventions for how builtins should support subclassing, typically aren't mentioned in that spec, even informally. You have to read between the lines. (It is a slightly aggravating standard, in some respects. Aren't they all.)

@domenic
Copy link
Member

domenic commented Nov 20, 2018

Yeah, this is definitely not explicit (and not tested). We should probably for now add a new line to https://streams.spec.whatwg.org/#conventions, plus some tests.

Of note, #963 would actually make this worse, because https://heycam.github.io/webidl/#interface-object does not do the right thing yet. That's whatwg/webidl#533

@ricea
Copy link
Collaborator

ricea commented Nov 21, 2018

If you override the constructor, but don't call super(), should IsReadableStream() still return true?

@domenic
Copy link
Member

domenic commented Nov 21, 2018

Nope, calling super() is essential. (This is how it works other ES and Web IDL stuff, apart from when ES stuff is generic.)

@ricea
Copy link
Collaborator

ricea commented Nov 22, 2018

@yutakahirano added a test for ReadableStream in https://chromium-review.googlesource.com/c/chromium/src/+/1347643. I've got tests for TransformStream and WritableStream ready, but I'm waiting for web-platform-tests/wpt#14172 to land first.

@MattiasBuelens
Copy link
Collaborator

@ricea web-platform-tests/wpt#14172 finally went green, Firefox stability tests took a long time. Feel free to merge it, then you can rebase your new tests. 🙂

@ricea
Copy link
Collaborator

ricea commented Nov 26, 2018

Subclassing tests for WritableStream and TransformStream landing soon at web-platform-tests/wpt#14228.

@MattiasBuelens
Copy link
Collaborator

@ricea Are you planning to update the ReadableStream is extendable test to align more with the new tests from web-platform-tests/wpt#14228? I think it'd be nicer if all three classes had similar tests.

@ricea
Copy link
Collaborator

ricea commented Nov 26, 2018

@ricea Are you planning to update the ReadableStream is extendable test to align more with the new tests from web-platform-tests/wpt#14228? I think it'd be nicer if all three classes had similar tests.

Done: web-platform-tests/wpt#14235.

@Ms2ger
Copy link
Member

Ms2ger commented Mar 11, 2019

WebIDL should now do the same thing; could people check if Streams matches IDL's behaviour?

@ricea
Copy link
Collaborator

ricea commented Mar 12, 2019

WebIDL should now do the same thing; could people check if Streams matches IDL's behaviour?

Sorry, I didn't fully understand your request. Could you provide a link to the behaviour you want checked?

@Ms2ger
Copy link
Member

Ms2ger commented Mar 12, 2019

Probably any section that starts with "new", but it seems like the creation of these objects is not defined at all, so that makes the request: define how your constructors work (in particular wrt NewTarget and subclassing).

domenic added a commit that referenced this issue Apr 13, 2020
Normative changes, all stemming from the Web IDL adaptation:

* All classes are now exposed globally. Formerly, ReadableStreamDefaultReader, ReadableStreamBYOBReader, ReadableStreamDefaultController, ReadableByteStreamController, WritableStreamDefaultWriter, WritableStreamDefaultController, and TransformStreamDefaultController were not exposed. Closes #586.

* All classes now have [Symbol.toStringTag] properties. (At least, pending whatwg/webidl#357 resolution.) Closes #952.

* For the queuing strategy classes, their size and highWaterMark properties are now getters on the prototype, instead of data properties on the prototype and instance (respectively). Closes #1005. Note that the size function is not settable anymore, but highWaterMark has a setter.

* Some functions have changed their length property value.

* Some exceptions are thrown earlier, at argument-conversion time.

Editorial changes:

* All APIs are specified to using Web IDL now, instead of using a modified version of the ECMAScript specification conventions. We continue using abstract operations and completion records for now, and we have to drop down to the ECMAScript level in a couple places (notably for dealing with %ObjectPrototype% vs. null-prototype iteration result objects, and transferring array buffers). But overall this removes a lot of type-checking and conversion boilerplate from the specification.

* Individual abstract operations, constructors, methods, and properties no longer have their own heading. They are instead lumped together in sections. Closes #885.

* The constructors, methods, and properties are now documented in a per-class block, using the usual WHATWG "domintro" style. Closes #907.

* Abstract operations are now consistently alphabetized within their section. Closes #684.

* By using Bikeshed's <div algorithm> feature, we now get automatic identifier highlighting. Closes #687.

* Switched to 100-character line limits, 1-space indents, and omitting end tags, per WHATWG conventions.

* Removed usage of emu-algify in favor of using some more of Bikeshed's built-in features, plus manually annotating a few things.

* Switched to concise Bikeshed linking syntax, e.g. [=term=] and [$AbstractOp$].

* Eliminated a number of utility abstract operations, especially around calling functions, by better using Web IDL.

Other bug fixes:

* Web IDL makes constructor behavior clear, so this closes #965.
domenic added a commit that referenced this issue Apr 13, 2020
Normative changes, all stemming from the Web IDL adaptation:

* All classes are now exposed globally. Formerly, ReadableStreamDefaultReader, ReadableStreamBYOBReader, ReadableStreamDefaultController, ReadableByteStreamController, WritableStreamDefaultWriter, WritableStreamDefaultController, and TransformStreamDefaultController were not exposed. Closes #586.

* All classes now have [Symbol.toStringTag] properties. (At least, pending whatwg/webidl#357 resolution.) Closes #952.

* All methods and accesors are now enumerable, per Web IDL defaults, instead of non-enumerable, per ECMAScript defaults.

* For the queuing strategy classes, their size and highWaterMark properties are now getters on the prototype, instead of data properties on the prototype and instance (respectively). Closes #1005. Note that the size function is not settable anymore, but highWaterMark has a setter.

* Some functions have changed their length property value.

* Some exceptions are thrown earlier, at argument-conversion time.

Editorial changes:

* All APIs are specified to using Web IDL now, instead of using a modified version of the ECMAScript specification conventions. We continue using abstract operations and completion records for now, and we have to drop down to the ECMAScript level in a couple places (notably for dealing with %ObjectPrototype% vs. null-prototype iteration result objects, and transferring array buffers). But overall this removes a lot of type-checking and conversion boilerplate from the specification.

* Individual abstract operations, constructors, methods, and properties no longer have their own heading. They are instead lumped together in sections. Closes #885.

* The constructors, methods, and properties are now documented in a per-class block, using the usual WHATWG "domintro" style. Closes #907.

* Abstract operations are now consistently alphabetized within their section. Closes #684.

* By using Bikeshed's <div algorithm> feature, we now get automatic identifier highlighting. Closes #687.

* Switched to 100-character line limits, 1-space indents, and omitting end tags, per WHATWG conventions.

* Removed usage of emu-algify in favor of using some more of Bikeshed's built-in features, plus manually annotating a few things.

* Switched to concise Bikeshed linking syntax, e.g. [=term=] and [$AbstractOp$].

* Eliminated a number of utility abstract operations, especially around calling functions, by better using Web IDL.

Other bug fixes:

* Web IDL makes constructor behavior clear, so this closes #965.
domenic added a commit that referenced this issue Apr 13, 2020
Normative changes, all stemming from the Web IDL adaptation:

* All classes are now exposed globally. Formerly, ReadableStreamDefaultReader, ReadableStreamBYOBReader, ReadableStreamDefaultController, ReadableByteStreamController, WritableStreamDefaultWriter, WritableStreamDefaultController, and TransformStreamDefaultController were not exposed. Closes #586.

* All classes now have [Symbol.toStringTag] properties. (At least, pending whatwg/webidl#357 resolution.) Closes #952.

* All methods and accesors are now enumerable, per Web IDL defaults, instead of non-enumerable, per ECMAScript defaults.

* For the queuing strategy classes, their size and highWaterMark properties are now getters on the prototype, instead of data properties on the prototype and instance (respectively). Closes #1005. Note that the size function is not settable anymore, but highWaterMark has a setter.

* Some functions have changed their length property value.

* Some exceptions are thrown earlier, at argument-conversion time.

Editorial changes:

* All APIs are specified to using Web IDL now, instead of using a modified version of the ECMAScript specification conventions. We continue using abstract operations and completion records for now, and we have to drop down to the ECMAScript level in a couple places (notably for dealing with %ObjectPrototype% vs. null-prototype iteration result objects, and transferring array buffers). But overall this removes a lot of type-checking and conversion boilerplate from the specification.

* Individual abstract operations, constructors, methods, and properties no longer have their own heading. They are instead lumped together in sections. Closes #885.

* The constructors, methods, and properties are now documented in a per-class block, using the usual WHATWG "domintro" style. Closes #907.

* Abstract operations are now consistently alphabetized within their section. Closes #684.

* By using Bikeshed's <div algorithm> feature, we now get automatic identifier highlighting. Closes #687.

* Switched to 100-character line limits, 1-space indents, and omitting end tags, per WHATWG conventions.

* Removed usage of emu-algify in favor of using some more of Bikeshed's built-in features, plus manually annotating a few things.

* Switched to concise Bikeshed linking syntax, e.g. [=term=] and [$AbstractOp$].

* Eliminated a number of utility abstract operations, especially around calling functions, by better using Web IDL.

Other bug fixes:

* Web IDL makes constructor behavior clear, so this closes #965.
domenic added a commit that referenced this issue Jun 11, 2020
Closes #963.

Normative changes to widely-implemented features, roughly in order of most disruptive to least-disruptive:

* For the queuing strategy classes, their size and highWaterMark properties are now getters on the prototype, instead of data properties on the prototype and instance (respectively). Closes #1005. In particular this means that attempts to set either of them post-creation will throw a TypeError. Chromium already ships these semantics.

* Functions which take a dictionary no longer accept non-objects.

* For the queuing strategy classes, their highWaterMark property will no longer return a non-number from their highWaterMark properties, if one was passed to the constructor. Instead, NaN will be returned.

* All methods and accessors are now enumerable, per Web IDL defaults, instead of non-enumerable, per ECMAScript defaults.

* All classes are now exposed globally. Formerly, ReadableStreamDefaultReader, ReadableStreamBYOBReader, ReadableStreamDefaultController, ReadableByteStreamController, WritableStreamDefaultWriter, WritableStreamDefaultController, and TransformStreamDefaultController were not exposed. Closes #586.

* All classes now have [Symbol.toStringTag] properties. Closes #952.

* Some functions have changed their length property value.

* Some exceptions are thrown earlier, at argument-conversion time.

* Property lookup in options arguments now happens earlier, at argument-conversion time, and in alphabetical order, per dictionary rules.

Normative changes to unimplemented features:

* ReadableStream's getIterator() method has been renamed to values() as part of adopting Web IDL's infrastructure for async iterators.

* The byobRequest property on ReadableByteStreamController now returns null when there is no BYOB request, instead of returning undefined.

* The view property on ReadableStreamBYOBRequest now returns null when the view cannot be written into, instead of returning undefined.

* Various byte-stream-related APIs that used to specifically prohibit detached buffers now check for zero-length views or buffers, which is a more general category.

* The async iterator's next() and return() methods now behave more like async generators, e.g. returning promises fulfilled with { value: undefined, done: true } after return()ing the iterator, instead of returning a rejected promise.

Editorial changes:

* All APIs are specified to using Web IDL now, instead of using a modified version of the ECMAScript specification conventions. We continue using abstract operations and completion records for now, and we have to drop down to the ECMAScript level in a couple places (notably for dealing with %ObjectPrototype% vs. null-prototype iteration result objects, and transferring array buffers). But overall this removes a lot of type-checking and conversion boilerplate from the specification. Closes #963. Closes #1017. See #1036 for further followup on the iteration result objects.

* Individual abstract operations, constructors, methods, and properties no longer have their own heading. They are instead lumped together in sections. Closes #885.

* The constructors, methods, and properties are now documented in a per-class block, using the usual WHATWG "domintro" style. Closes #907.

* Abstract operations are now consistently alphabetized within their section. Closes #684.

* By using Bikeshed's <div algorithm> feature, we now get automatic identifier highlighting. Closes #687.

* Switched to 100-character line limits, 1-space indents, and omitting end tags, per WHATWG conventions.

* Removed usage of emu-algify in favor of using some more of Bikeshed's built-in features, plus manually annotating a few things.

* Switched to concise Bikeshed linking syntax, e.g. [=term=] and [$AbstractOp$].

* Eliminated a number of utility abstract operations, especially around calling functions, by better using Web IDL.

Other bug fixes:

* Web IDL makes constructor behavior clear, so this closes #965.
yutakahirano pushed a commit to yutakahirano/streams that referenced this issue Jun 3, 2021
Closes whatwg#963.

Normative changes to widely-implemented features, roughly in order of most disruptive to least-disruptive:

* For the queuing strategy classes, their size and highWaterMark properties are now getters on the prototype, instead of data properties on the prototype and instance (respectively). Closes whatwg#1005. In particular this means that attempts to set either of them post-creation will throw a TypeError. Chromium already ships these semantics.

* Functions which take a dictionary no longer accept non-objects.

* For the queuing strategy classes, their highWaterMark property will no longer return a non-number from their highWaterMark properties, if one was passed to the constructor. Instead, NaN will be returned.

* All methods and accessors are now enumerable, per Web IDL defaults, instead of non-enumerable, per ECMAScript defaults.

* All classes are now exposed globally. Formerly, ReadableStreamDefaultReader, ReadableStreamBYOBReader, ReadableStreamDefaultController, ReadableByteStreamController, WritableStreamDefaultWriter, WritableStreamDefaultController, and TransformStreamDefaultController were not exposed. Closes whatwg#586.

* All classes now have [Symbol.toStringTag] properties. Closes whatwg#952.

* Some functions have changed their length property value.

* Some exceptions are thrown earlier, at argument-conversion time.

* Property lookup in options arguments now happens earlier, at argument-conversion time, and in alphabetical order, per dictionary rules.

Normative changes to unimplemented features:

* ReadableStream's getIterator() method has been renamed to values() as part of adopting Web IDL's infrastructure for async iterators.

* The byobRequest property on ReadableByteStreamController now returns null when there is no BYOB request, instead of returning undefined.

* The view property on ReadableStreamBYOBRequest now returns null when the view cannot be written into, instead of returning undefined.

* Various byte-stream-related APIs that used to specifically prohibit detached buffers now check for zero-length views or buffers, which is a more general category.

* The async iterator's next() and return() methods now behave more like async generators, e.g. returning promises fulfilled with { value: undefined, done: true } after return()ing the iterator, instead of returning a rejected promise.

Editorial changes:

* All APIs are specified to using Web IDL now, instead of using a modified version of the ECMAScript specification conventions. We continue using abstract operations and completion records for now, and we have to drop down to the ECMAScript level in a couple places (notably for dealing with %ObjectPrototype% vs. null-prototype iteration result objects, and transferring array buffers). But overall this removes a lot of type-checking and conversion boilerplate from the specification. Closes whatwg#963. Closes whatwg#1017. See whatwg#1036 for further followup on the iteration result objects.

* Individual abstract operations, constructors, methods, and properties no longer have their own heading. They are instead lumped together in sections. Closes whatwg#885.

* The constructors, methods, and properties are now documented in a per-class block, using the usual WHATWG "domintro" style. Closes whatwg#907.

* Abstract operations are now consistently alphabetized within their section. Closes whatwg#684.

* By using Bikeshed's <div algorithm> feature, we now get automatic identifier highlighting. Closes whatwg#687.

* Switched to 100-character line limits, 1-space indents, and omitting end tags, per WHATWG conventions.

* Removed usage of emu-algify in favor of using some more of Bikeshed's built-in features, plus manually annotating a few things.

* Switched to concise Bikeshed linking syntax, e.g. [=term=] and [$AbstractOp$].

* Eliminated a number of utility abstract operations, especially around calling functions, by better using Web IDL.

Other bug fixes:

* Web IDL makes constructor behavior clear, so this closes whatwg#965.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

5 participants