Jussi Kalliokoski (2014-06-30T09:37:27.000Z)
dignifiedquire at gmail.com (2014-06-30T13:44:49.357Z)
This is probably an absurd idea and I have no idea if it can be actually made to work for host objects, but wanted to throw it in the air to see if it has any viability and could be polished. As we all know, mixins are a strongly ingrained pattern in JS out in the wild. One notable example is the EventEmitter in node and the numerous browserland alternatives. The main benefit of mixins is pretty much that they allow multiple inheritance. The common mixin design pattern is something like: ```js function A () { this.x = 1; } function B () { this.y = 2; A.apply(this, arguments); } ``` So you have the constructor function that initializes the state of the instance, and doesn't care whether the state is applied to an instance of the class or even a plain object. Could subclassing be described in terms of mixins? After all, the problems we're having here and the reason we're trying to make complex solutions like deferred creation step is to hide the uninitialized state. But say, in addition to `@@create`, we had `@@initialize` which would just add the hidden state to any given object bound to `this`. This can be done in terms of for example assigning a host object or other private state into one symbol, or multiple symbols to hold different private variables, or an engine-specific way; it doesn't matter because it's an implementation detail that is not visible to the userland. However, the key thing is that it could be applied to any given object, not just instances of the host object. That sidesteps the whole problem of uninitialized state, because you only have objects that have no state related to the host object or objects that have initialized state of the host object. So let's say the default value of `@@initialize` was as follows: ```js super(...arguments); ``` That is, just propagate through the `@@initialize` methods in the inheritance chain. Then the default value of `@@create` could be described as follows: ```js var instance = Object.create(ThisFunction.prototype); ThisFunction[@@initialize].apply(instance, arguments); return instance; ``` As an example, here's how you could self-host Map in these terms: https://gist.github.com/jussi-kalliokoski/5ef02ef90c6cbb8c1a70 . In the example, the uninitialized state is never revealed. Simplicity is not the only gain from this approach, since it also opens the door to multiple inheritance, e.g. let's say you wanted a Map whose contents you can append to a DOM node: ```js class DomBag { [@@initialize] () { DocumentFragment[@@initialize].apply(this); Map[@@initialize].apply(this, arguments); for ( let node of this.values ) { DocumentFragment.prototype.appendChild.call(this, value); } } get: Map.prototype.get has: Map.prototype.has set (key, value) { if ( this.has(key) ) { this.removeChild(this.get(key)); } Map.prototype.set.call(this, key, value); DocumentFragment.prototype.appendChild.call(this, value); } remove (key) { if ( this.has(key) ) { this.removeChild(this.get(key)); } Map.prototype.remove.call(this, key); } } var bag = new DomBag([ ["foo", document.createElement("foo")], ["bar", document.createElement("bar")] ]); document.body.appendChild(bag); ``` So the core idea of the proposal is to make host objects completely unobservable. A DOMElement instance for example is no longer a host object; it's a normal object with `__proto__` assigned to `DOMElement.prototype`, however it contains a private reference to a host object that is not observable to userland in any way. There's obvious problems that need to be thought of, mostly because of DOM, like if you initialize two DOM node things on the same object, and then append that node somewhere. However, if we think of it in terms of symbols, we can have a symbol that represents the host object that gets applied to the tree when the object is applied, and the `@@initialize` of these nodes assigns a host object to that symbol, of course the assignment in the latter `@@initialize` overrides the one in the former. WDYT?