tc39 / proposal-mixins

A template for ECMAScript proposals
MIT License
61 stars 2 forks source link

The fact that a mixin is used should not be public information #12

Open theScottyJam opened 3 years ago

theScottyJam commented 3 years ago

This post has been updated to try and re-word it in a clearer way.

I see that this proposal is jumping through some hoops in order to make it expose which mixin created a particular node on the prototype (through Symbol.mixin), and to make instanceof work against the mixin function. What if ... we just didn't do that? What if we did what we could reasonably do to make it difficult to figure out who's using what mixins?


Inheritance is two different features combined into one:

Because polymorphism can be useful, many people get into the habit of creating inheritance hierarchies in order to have their library support it. But, due to how inheritance is designed, you can't create this public hierarchy without also being forced to actually inherit behaviors. In other words, the ability to inherit behaviors often gets overused, simply because people want to make public hierarchies for polymorphic purposes. I've certainly fallen into this trap multiple times in different languages - creating inheritance hierarchies for the primary purpose of supporting polymorphism, not because I actually needed to inherit behaviors.

I'm inspired by the go language's approach to inheritance. They don't have it. Instead, they've split the two objectives of inheritance in half. If you want polymorphism, you have to use interfaces. If you want to inherit behavior, you have to use a feature they provide called "embedding", which is pretty much the same as inheritance, except they don't publicly expose the fact that a particular class is using this embedding feature, nor does it automatically create a polymorphic relationship (i.e. aside from reflection, there's no "instanceof" check the public can do to see if a particular class embedded a specific set of behaviors).

Looking at Javascript's current proposals, I see that it has the potential to follow Go's lead, and cleanly split inheritance into two separate concepts:

I'm advocating that we treat mixins as an implementation detail, that the library author can freely change up without affecting the end user's code. This provides library authors with a lot more flexibility than otherwise possible. If they wish to provide the end-user with some kind of polymorphic behavior, they can have their classes conform to a protocol, and expose the protocol to the end-user, so the end-user can do "implements" checks.

On the extreme end of things, this could move us in a direction that will eventually lead to the (near) death of instanceof and non-mixin inheritance. Existing publicly exposed inheritance hierarchies are here to stay, but new ones can start using mixins and protocols instead.