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

Define that interface objects are constructors #698

Open
Ms2ger opened this issue Mar 26, 2019 · 13 comments
Open

Define that interface objects are constructors #698

Ms2ger opened this issue Mar 26, 2019 · 13 comments

Comments

@Ms2ger
Copy link
Member

Ms2ger commented Mar 26, 2019

ES claims the following (twice):

Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function.

We don't normatively identify the interface object as a constructor, even if it has a [Constructor]. I guess we should.

A less obvious question is what we should do if there's no [Constructor]. Right now, I think we're aiming to install a [[Construct]] internal method that always throws, but that makes the interface object pass IsConstructor().

@bzbarsky
Copy link
Collaborator

unless otherwise specified in the description of a particular function

This is the key, no? https://heycam.github.io/webidl/#Constructor specifies otherwise:

If the [Constructor] extended attribute appears on an interface, it indicates that the interface object for this interface will have an [[Construct]] internal method

So I think we're good here: thing with a [Constructor] have [[Construct]] and things without do not, as desired.

@bzbarsky
Copy link
Collaborator

Though I guess that leaves open the question of the no-[Constructor] case. I just checked Gecko, and it does have a [[Constructor]] in that case, albeit one that always throws. I wonder whether the output of IsConstructor() is observable, other than by the exceptions that get thrown.

@bzbarsky
Copy link
Collaborator

I guess you could do something where you use a DOM interface object as the .constructor of an array and see what happens in https://tc39.github.io/ecma262/#sec-arrayspeciescreate step 6.

@bzbarsky
Copy link
Collaborator

And also whether a proxy for a DOM interface object ends up with a construct trap being called. So simple testcase:

<script>
  var p = new Proxy(Node, { construct: () => console.log("constructing") });
  new p()
</script>

@bzbarsky
Copy link
Collaborator

On that testcase, Chrome and Firefox log "constructing"; Safari does not (and the exception it throws is about p not being a constructor). Yay interop. ;)

But OK, if we want to spec Chrome/Firefox behavior here then we need to change something in the idl spec.

@bzbarsky
Copy link
Collaborator

And admittedly it would be good if the "is a constructor" bit was near the bit that defines the steps, not way off somewhere else...

@domenic
Copy link
Member

domenic commented Apr 3, 2019

I've always assumed they had constructors (and [[Construct]] methods), just throwing ones.

I think it'd be very strange to have callable interface objects exist at all, and be reachable via the .constructor property, if they are not also [[Construct]]able.

In practice it doesn't matter much, but I do prefer keeping [[Construct]] and just saying that it throws for things without a constructor in the IDL.

@bzbarsky
Copy link
Collaborator

bzbarsky commented Apr 3, 2019

There was an interesting question about feature detection that was raised the other day: how to detect a change from "no [Constructor]" to "no-arg [Constructor]". Right now, I think "call the constructor and see if it throws" is the only way in Firefox and Chrome. The Proxy thing above could be used if we changed whether [[Construct]] happens...

But maybe this is enough of an edge case that it's not an issue.

@rniwa would Safari be open to changing its behavior here, or do you know whom I should be asking about it?

@rniwa
Copy link

rniwa commented Apr 3, 2019

What's the benefit of implementing Chrome/Firefox behavior here?

@bathos
Copy link
Contributor

bathos commented Oct 3, 2019

FWIW, it seems there’s a number of ways to observe this distinction beyond just Proxy — pretty much anywhere IsConstructor is used, I guess. In addition to peeking out through various programmatic APIs, it can also impact evaluation of ‘bare’ syntax (third example below). Each of the following statements will throw a TypeError if Foo[[Construct]] is absent, but will not throw if it’s present:

Reflect.construct(Bar, [], Foo);

customElements.define('x-x', Foo);

class Bar extends Foo {}

Usually it’s throw vs don’t throw, but sometimes potentially neither throws but they still do other different things:

// If Foo[[Construct]] is present, (attempts) returning new Foo.
// If Foo[[Construct]] is absent, returns new Array.

Array.from.call(Foo, []);

// In practice here, the first case throws for the specific Web IDL issue under discussion,
// though it’s the reverse of the other cases (i.e. throw when [[Construct]] _is_ present).

I think it'd be very strange to have callable interface objects exist at all, and be reachable via the .constructor property, if they are not also [[Construct]]able.

I agree.

@shvaikalesh
Copy link
Contributor

shvaikalesh commented Oct 20, 2020

@rniwa would Safari be open to changing its behavior here, or do you know whom I should be asking about it?

This behavior was changed in JSDOMConstructorNotConstructable should be a constructor, aligning Safari with Chrome/Firefox.

@domenic
Copy link
Member

domenic commented Oct 20, 2020

Thanks @shvaikalesh! Do you know if there are web platform tests for this?

I looked into how we would update the Web IDL spec to be explicit about this, and it's still kinda unclear to me, largely because the ES spec is unclear. I will open an issue on tc39/ecma262 asking for guidance.

@shvaikalesh
Copy link
Contributor

Do you know if there are web platform tests for this?

There are tests asserting that (class extends HTML___Element {}) doesn't throw, and that's it.

idlharness.js has a FIXME for implementing [[Construct]] check.

domenic added a commit to web-platform-tests/wpt that referenced this issue Mar 15, 2021
domenic added a commit to web-platform-tests/wpt that referenced this issue Apr 26, 2021
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue May 8, 2021
…=testonly

Automatic update from web-platform-tests
Test IsConstructor for all interfaces

Part of whatwg/webidl#698.

--

wpt-commits: 943bb28f67e315fbc16a203479ffbadd27b7e0ba
wpt-pr: 28089
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

6 participants