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

Differences between "normal" platform objects and "normal" JavaScript classes #226

Open
annevk opened this issue Nov 7, 2016 · 12 comments
Labels

Comments

@annevk
Copy link
Member

annevk commented Nov 7, 2016

Some are mentioned in tc39/proposals#30 (comment) by @domenic:

  • enumerable (Web IDL) vs. non-enumerable (conventional for ES)
  • statics being functions (Web IDL) vs. methods (conventional for ES)

I believe in Gecko at least typeof will also be different.

This means for instance that https://streams.spec.whatwg.org/ cannot be done in IDL and that https://url.spec.whatwg.org/ expressed in TC39-language would have slightly different behavior.

That seems suboptimal, especially if there's still hope to eventually bridge the chasm somehow.

As a start, having it clearly documented how "normal" platform objects differ from "normal" JavaScript classes would be good.

@domenic
Copy link
Member

domenic commented Nov 7, 2016

I believe in Gecko at least typeof will also be different.

No, typeof will always be object. You might be thinking about Object.prototype.toString.call(obj). But even there ES built-ins use Symbol.toStringTag to customize that. (But, normal JS classes do not.)

@bzbarsky
Copy link
Collaborator

bzbarsky commented Nov 7, 2016

enumerable (Web IDL) vs. non-enumerable (conventional for ES)

There has been talk of adding something to IDL to control enumerability, so on a technical level we can "solve" this.

The more fundamental problem is the inconsistency in the platform and the lack of a credible plan to bridge it. :( ES classes are basically defined to look more like ES builtins here, while IDL standardized de-facto behavior of existing browser builtins like DOM. The web definitely depends on enumerability for some of the DOM APIs, but I don't know that anyone has a good list of which ones. Clearly we could make new ones non-enumerable, at the cost of even more confusion, but we could just as easily make new TC39 stuff enumerable, at the cost of even more confusion. Or maybe neither one is more confusing than what we have now, since most people have no clue which things are ES and which things are IDL-defined anyway. I don't see any non-sucky outcomes here, honestly...

statics being functions (Web IDL) vs. methods (conventional for ES)

In the sense that ES statics will examine their "this" object (the constructor object) for some state?

We could quite trivially change this on the IDL side in the sense of passing the "this" object to the spec prose defining the IDL static, which would allow it to use it if it wants. In practice, there's typically nothing the spec prose wants out of that object, so the distinction is moot in most cases. In the specific case of URLSearchParams there are no statics to start with, so the distinction is even more moot. ;)

I believe in Gecko at least typeof will also be different.

I'm not aware of anything like this.

having it clearly documented how "normal" platform objects differ from "normal" JavaScript classes

The most obvious difference is that platform objects have branding checks and JS classes normally don't [1]. JS builtins, which are somewhat like JS clases in some ways and different in others, sometimes do and sometimes don't.

[1] For the same reason they don't normally have interesting toString behavior: you can do it, but it takes some extra effort and most people wouldn't bother.

@annevk
Copy link
Member Author

annevk commented Nov 7, 2016

Sorry, I meant instanceof, not typeof.

@annevk
Copy link
Member Author

annevk commented Nov 7, 2016

@bzbarsky the URL object has a static defined in the File API (createObjectURL).

@domenic
Copy link
Member

domenic commented Nov 7, 2016

The statics-being-methods thing mostly impacts whether they work when extracted or not. E.g. const resolve = Promise.resolve will not work. But const cOU = URL.createObjectURL will work.

@bzbarsky
Copy link
Collaborator

bzbarsky commented Nov 7, 2016

Sorry, I meant instanceof, not typeof

Ah. That's something that can be expressed in ES anyway using @@hasInstance (though typically is not, of course).

URL.createObjectURL and Promise.resolve are fundamentally different beasts: the former creates a string, while the latter creates a Promise. I agree that statics that create an object of the type being defined should be methods, to play nice with subclassing. With that in mind, we should change IDL to pass "this" to statics; if we don't have an existing issue on that, let's get one filed and just fix this. That will allow specs to do the right thing here. Whether we can change existing specs to the method semantics, I'm not sure. :(

But I'm pretty sure this mostly (only?) affects statics that create an object of the type they're defined on. I just looked (well, had our binding codegen look) through Gecko's IDL looking for such statics. The full list is:

  • IDBKeyRange.only
  • IDBKeyRange.lowerBound
  • IDBKeyRange.upperBound
  • IDBKeyRange.upperBound
  • IDBLocaleAwareKeyRange.bound
  • Response.error
  • Response.redirect

It's too bad no one raised this issue about statics when fetch's Response was being specified. :( IDB not raising it I'm not surprised by, of course; there weren't many ES-aware people involved in that.

@bzbarsky
Copy link
Collaborator

bzbarsky commented Nov 7, 2016

Oh, and looks like IDBLocaleAwareKeyRange is not even on by default yet...

I can't speak to whether someone would want to subclass IDBKeyRange in practice, but subclassing Response seems like a totally reasonable thing to do. :(

@littledan
Copy link
Collaborator

It would be really great if the standards venue didn't affect the shape of the resulting API. Sounds like the three things raised in this thread have a path towards resolution. Would it be reasonable to start a policy of doing things in a more ES-type style when new APIs come up (sounds like enumerability is the big one here)? For enumerability on the JS side, there seems to be a strong feeling in TC39 that we couldn't add more enumerable methods to existing objects without breaking existing code.

@bzbarsky
Copy link
Collaborator

bzbarsky commented Nov 7, 2016

It would be really great if the standards venue didn't affect the shape of the resulting API.

Yes, it would, though we have a huge legacy of it having done just that. We had this exact conversation 4-5 years ago (not you and I, but various people involved in ES and web specs) and absolutely nothing changed as a result. :(

Would it be reasonable to start a policy of doing things in a more ES-type style

Why not in a more IDL-type style? Honest question, not trolling.

For enumerability on the JS side, there seems to be a strong feeling in TC39 that we couldn't add more enumerable methods to existing objects without breaking existing code.

Oh, on the DOM side we can't remove enumerability from existing objects without breaking existing code. Or more precisely, we know there are some we can't remove it from, but we don't know which things are in that bucket, necessarily.

This is all be a discussion about new things that are added; for existing stuff we're stuck with what we have, I'm afraid.

@littledan
Copy link
Collaborator

@bzbarsky Definitely agree about not changing existing things.

Why not in a more IDL-type style? Honest question, not trolling.

The reason we don't make new things enumerable in ECMAScript (I believe) is that we're concerned about breaking the web. Maybe this claim that new enumerable properties the web would break isn't true, if other parts of the web platform have been getting away with it, but it makes me concerned.

@bzbarsky
Copy link
Collaborator

bzbarsky commented Nov 8, 2016

I think this claim is perhaps true for new properties added on existing objects, and especially on Array.prototype and Object.prototype, because those two would break a lot of for-in loops.

I think adding enumerable stuff elsewhere would not have broken the web, and adding it on entirely new things is very unlikely to do so.

@littledan
Copy link
Collaborator

(This issue could use the jsidl tag.)

@annevk annevk added the jsidl label Dec 10, 2018
domenic added a commit that referenced this issue Apr 23, 2020
This fixes https://www.w3.org/Bugs/Public/show_bug.cgi?id=28244,
aligning Web IDL objects with the built-in ECMAScript objects (see
#226), and updates the spec to match 1/3 engines (Chromium) instead of
0/3 as it currently does.
domenic added a commit that referenced this issue Apr 23, 2020
This fixes https://www.w3.org/Bugs/Public/show_bug.cgi?id=28244,
aligning Web IDL objects with the built-in ECMAScript objects (see
#226), and updates the spec to match 1/3 engines (Chromium) instead of
0/3 as it currently does. The other two engines are willing to align,
however!

Tests: web-platform-tests/wpt#23140
domenic added a commit that referenced this issue Apr 23, 2020
This fixes https://www.w3.org/Bugs/Public/show_bug.cgi?id=28244,
aligning Web IDL objects with the built-in ECMAScript objects (see
#226), and updates the spec to match 1/3 engines (Chromium) instead of
0/3 as it currently does. The other two engines are willing to align,
however!

Tests: web-platform-tests/wpt#23140
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

4 participants