-
Notifications
You must be signed in to change notification settings - Fork 47
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
Classes (WebIDL interfaces) should only be used when you have both data and behavior #11
Comments
I guess you will explain this a bit, but can you give me a quick tl;dr example/why behavior-only interfaces should be represented as JS objects? Not really getting what you mean. |
Sure. If there's no state to mutate, then it's just a bunch of functions. (Note: functions, not methods.) And we represent a collection of named functions in JS by e.g. |
Thanks for the clarification, @domenic. It would indeed be nice to be able to express this somehow in WebIDL. There is something that does worry me tho: It's usually pretty clear when you are returning "data" objects, but I think it gets trickier to design objects that are purely behavioral - as it's easy to add accessor properties on them. Having them as classes makes it easier to allow others to extend them (either directly through the prototype or through |
I see what you're saying. However, in my experience, the behavior-only objects in web specs are usually pretty clear: they're often singletons, and often have only one or two functions. As such, a shared prototype is not useful anyway in those cases, reinforcing the idea that a class is not the right tool for the job. |
Should WebIDL namespaces be used for the behavior-only case? |
@dbaron that makes sense to me.
|
Remove redundant suggestions
Could you please point us to these examples? It would be very helpful in writing this up. |
So we discussed in today's call and we all agree we should write something. Probably this isn't a webidl specific thing. The principle is about the API shape. @LeaVerou will work on this with @cynthia and @atanassov . |
@LeaVerou, I put together a gist with all the IDL in wpt/interfaces/*.idl... should hopefully help with finding examples there: Looking quickly.... There are situations where using an interface (for data) is unavoidable, like with Anyway, hopefully the above helps with finding examples! |
@LeaVerou, a couple of examples:
There are some problems though, like there was a recent case where an APIs wanted to use the dictionary So, it's important to also thing about when/where a data object might be used (and if it will only ever be a return type). Otherwise, you can end up with (somewhat) clunky, but not tooooo baaaaaad, |
I think these days we would have used a dictionary for |
Oh, yes, I should have included |
Another example where I may have screwed up: |
Discussing with in a breakout with @cynthia, we realized we both think the guidance should be more nuanced: First, we do agree that classes with only behavior don't make sense, that's just a collection of functions. We are not so sure about objects that are only data. First, many of these objects may eventually evolve to contain behavior. Once you have state, it's easy to come up with methods to mutate it or make computations on it, and whether you have these from the get go or not should not dictate such a fundamental architectural decision. We are definitely in agreement that "input-only" objects (e.g. options dictionaries) should always be plain objects (WebIDL dictionaries). For example, WebRTC APIs are terrible offenders here. Also, APIs accepting objects that are only or mainly data, should also accept plain objects, for better developer ergonomics (e.g. the However, class instances can be useful when objects are returned from an API and thus, can be passed around, as an object being an instance of a class is an implicit contract that it follows a certain schema (yes, that can be manipulated in JS, but everything can be). It's far easier for a developer to do e.g. Another argument against that came up against using classes for data objects is namespace pollution, but this can be mitigated by these classes being hung on to the relevant APIs, rather than the global scope. E.g. In terms of defining or editing principles, some that could come out of this could be: (Note: We use the term "Data-centric class" to describe a class whose instances primarily contain data, and potentially some auxiliary methods, or no methods at all)
|
Re. "Do not define classes that only have functions (e.g. never another
In this discussion, objects such as |
Additionally, although https://github.com/tc39/proposal-first-class-protocols is still stage 1 and too early to base design principles around, I'd personally find |
What can’t be is private host-controlled state associated with the object, so an operation that takes Unfortunately, it doesn’t seem like (many?) Web IDL APIs take advantage of that? For example |
Agreed, but how do you define "shouldn't really be a class"? I don't think whether it has methods or not is a good heuristic. Perhaps whether it could conceivably have methods in the future, but that's very handwavy. |
In today’s breakout we decided to draft some text for these:
There doesn’t yet seems to be enough consensus for this:
Whereas this doesn't seem to be much of a problem in existing APIs (as mentioned by @ptomato namespace objects are fine):
|
Math isn't a class, so I'm a bit confused why that's a problem. We also have JSON, Reflect, and Atomics that are all conceptually identical to Math. |
Yeah, that was a poor example, namespace objects are obviously fine. Basically, we don't want a constructible class, which holds no state but only behavior. We couldn't find any examples of this, but some people thought it may be good to document it anyway, but it's pretty low priority. |
|
|
Oh, excellent examples, thank you both!! |
I see a lot of classes that have only data, or have only behavior. Both of these cases should be represented by plain JS objects.
Edit by TAG: Current TAG thinking here
The text was updated successfully, but these errors were encountered: