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

Avoid exotic objects (e.g. named/indexed getters/setters) #16

Open
domenic opened this issue Jun 29, 2015 · 12 comments
Open

Avoid exotic objects (e.g. named/indexed getters/setters) #16

domenic opened this issue Jun 29, 2015 · 12 comments
Assignees
Labels
Status: Consensus to write We have TAG consensus about the principle but someone needs to write it (see "To Write" project) tc39-tracker Issues where TC39 input would be useful Topic: JS Topic: Web IDL Has to do with Web IDL
Projects

Comments

@domenic
Copy link
Member

domenic commented Jun 29, 2015

I just wrote up https://code.google.com/p/chromium/issues/detail?id=503971#c6 and it'd probably be worth capturing here.

@annevk
Copy link
Member

annevk commented Jun 29, 2015

See https://www.w3.org/Bugs/Public/show_bug.cgi?id=26986 which would make this more clearly a stupid idea from an IDL perspective.

@dbaron
Copy link
Member

dbaron commented Jul 26, 2017

@travisleithead points out that exotic object is defined in ECMA-262.

@torgo
Copy link
Member

torgo commented Jul 26, 2017

Reference an ecmascript definition. https://ecma-international.org/ecma-262/6.0/#sec-exotic-object

@torgo torgo added the Status: In Progress We're working on it but ideas not fully formed yet. label Jul 26, 2017
@torgo
Copy link
Member

torgo commented Jul 26, 2017

Something should go in section 2.

@torgo torgo assigned travisleithead and unassigned dbaron Jul 26, 2017
@domenic
Copy link
Member Author

domenic commented Jul 26, 2017

In IDL we have since renamed the objects so-defined "legacy platform objects"

Also, please use https://tc39.github.io/ecma262/.

@torgo torgo assigned cynthia and unassigned travisleithead Apr 6, 2018
@torgo torgo added Status: Consensus to write We have TAG consensus about the principle but someone needs to write it (see "To Write" project) and removed Status: In Progress We're working on it but ideas not fully formed yet. labels Apr 6, 2018
@torgo torgo assigned travisleithead and unassigned cynthia Apr 6, 2018
@travisleithead
Copy link
Contributor

Need to figure out how to relate the various -like constructs as well, e.g., maplike and setlike. How does the guidance for these differ from the general guidance around legacy platform objects? Presumably it's different guidance...

@travisleithead
Copy link
Contributor

@hober hober added the Topic: Web IDL Has to do with Web IDL label Jul 6, 2020
@torgo torgo added the Overtaken? This is an old issue that may no longer be relevant? label May 3, 2021
@LeaVerou LeaVerou added this to Unassigned in To Write Sep 16, 2021
@plinss plinss added this to the 2022-01-17-week milestone Jan 13, 2022
@plinss plinss removed this from the 2022-03-21-F2F-Not Edinburgh milestone May 2, 2022
@LeaVerou
Copy link
Member

LeaVerou commented Jun 25, 2022

Since we have a long-term goal of publishing a subset of the design principles for web developers, I wondered: are exotic objects an antipattern for JS libraries as well, or only for Web Platform APIs?

@LeaVerou
Copy link
Member

LeaVerou commented Jul 5, 2022

@plinss and I looked at this today during a breakout and we were not sure we understand exactly what is proposed to be an antipattern here. My understanding was that every API that uses keys that depend on current state is an antipattern according to the proposed principle, but the actual ES definition of exotic objects is more restricted.

If my understanding is correct, this would render APIs like the following antipatterns:

  • localStorage
  • AllCSSStyleDeclaration objects, including element.style
  • element.dataset
  • element.attributes

Is that the case?

@domenic
Copy link
Member Author

domenic commented Jul 6, 2022

My understanding was that every API that uses keys that depend on current state is an antipattern according to the proposed principle, but the actual ES definition of exotic objects is more restricted.

The ES definition is actually more expansive.

The only way to get object properties ("keys") which depend on the current state is by overriding the [[OwnPropertyKeys]]() internal method. And, any overridden internal method makes an object exotic by the ES definition. So, objects with custom keys are just one type of exotic object.

In practice on the web platform the two categories you identify are mostly equivalent, because as long as you define your objects using Web IDL, the primary way to make them exotic is by using indexed/named getters/setters/deleters. I.e., making their properties dynamic. This will make them into legacy platform objects.

For completeness: other less-relevant ways of using Web IDL to create exotic objects are:
  • Global objects are slightly exotic in that they have an overridden [[SetPrototypeOf]] to make their prototype immutable
  • Named property objects are a special category of exotic object which exist in Window's prototype chain

A final type of exotic object that you can create using Web IDL is the observable array exotic object. This was very carefully designed to implement best practices for exotic objects, essentially making it behave as much like an Array (which is another type of exotic object) as possible. People should be able to use observable arrays going forward, and thus avoid using indexed getters/setters to create their own new types of exotic objects.

If my understanding is correct, this would render APIs like the following antipatterns:

Yes.

An important point on CSStyleDeclaration, though. It is not exotic because of the various properties like fontSize, marginTop, etc. Those are defined as normal properties. There are a lot of them, but that's fine: it's a finite list, determined at "compile time", not at runtime. It is exotic instead because of the indexed getter, declaration[i], which returns the _i_th property name.

Perhaps relatedly, I saw in your recent post you cited color.lch.l as exotic. I'm not sure how that's implemented in your library, or if I've understood the example, but if I were to implement that as a web platform API, I think it would be doable without exotic objects. You'd have a finite (determined ahead of time) set of properties, such as color.lch and color.rgb and so on, each of which was an instance of a specific class, such as LCHColor and RGBColor, each of which have a finite (determined ahead of time) set of properties, such as l, c, h, and r, g, b. Nothing exotic needed; just a bunch of normal classes with normal properties.

@LeaVerou
Copy link
Member

LeaVerou commented Jul 6, 2022

Thank you for the clarifications. Are there any other DOM APIs that this would render antipatterns?

Perhaps relatedly, I saw in your recent post you cited color.lch.l as exotic. I'm not sure how that's implemented in your library, or if I've understood the example, but if I were to implement that as a web platform API, I think it would be doable without exotic objects. You'd have a finite (determined ahead of time) set of properties, such as color.lch and color.rgb and so on, each of which was an instance of a specific class, such as LCHColor and RGBColor, each of which have a finite (determined ahead of time) set of properties, such as l, c, h, and r, g, b. Nothing exotic needed; just a bunch of normal classes with normal properties.

Definitely related, as we tried to avoid named properties in the Color API exactly because of this proposed principle, but there is a significant API ergonomics difference between color.get("l") and color.l.
No, a predefined set of getters would not work, as you can register new color spaces at runtime. That is also why we don't want to have Color subclasses like that.

Did you see this question btw?:

Since we have a long-term goal of publishing a subset of the design principles for web developers, I wondered: are exotic objects an antipattern for JS libraries as well, or only for Web Platform APIs?

@domenic
Copy link
Member Author

domenic commented Jul 8, 2022

Are there any other DOM APIs that this would render antipatterns?

Yes, anything that uses getter or setter annotations. The best way to find this that I'm familiar with is code-searching your favorite browser's IDL files, e.g. here are the results for Chromium.

Since we have a long-term goal of publishing a subset of the design principles for web developers, I wondered: are exotic objects an antipattern for JS libraries as well, or only for Web Platform APIs?

In general I would say they are. They conflate the interface of a class with its data. Besides that being a confusing problem and an issue for theoretical purity, it has practical issues. E.g. with localStorage, what happens if you try to store an item named getItem? Then is localStorage.getItem a function, or is it the stored item? Similarly with HTMLCollection and nodes with id="length". (There are well-defined answers to these questions, but the fact that they have to be asked is a sign of bad design.) Even if you think your class has very few parts of its interface, you're still stepping on the basic parts of the interface that all JavaScript objects share, e.g. toString(), hasOwnProperty(), constructor, etc. (So e.g. in your color example, I wonder what happens if someone defines a colorspace whose components are (toString, hasOwnProperty, constructor).)

For numeric-only cases, the reasoning is a bit different, which is basically that developers expect indexed collections to behave as much as possible like arrays. So developers (and web spec authors) should really just use arrays when possible. Sometimes they need extra functionality, usually to observe changes; to do this they need to use very carefully-constructed proxies (like ObservableArray<T> does on the spec level).

@torgo torgo removed the Overtaken? This is an old issue that may no longer be relevant? label Sep 6, 2022
@LeaVerou LeaVerou added the tc39-tracker Issues where TC39 input would be useful label Apr 21, 2023
@torgo torgo moved this from Unassigned to cynthia in To Write Oct 3, 2023
@torgo torgo modified the milestones: 2023-10-02-week, 2024-06-03-week Jun 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Consensus to write We have TAG consensus about the principle but someone needs to write it (see "To Write" project) tc39-tracker Issues where TC39 input would be useful Topic: JS Topic: Web IDL Has to do with Web IDL
Projects
To Write
cynthia
Development

No branches or pull requests

10 participants