Jussi Kalliokoski (2014-06-30T09:37:27.000Z)
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:

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:

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:

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:

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?

Cheers,
Jussi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20140630/318fec38/attachment-0001.html>
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?