Definition mixins

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

Definition mixins

Raul-Sebastian Mihăilă

---------- Forwarded message ----------
From: dante federici <[hidden email]>
To: [hidden email]
Date: Mon, 27 Nov 2017 22:22:11 +0000
Subject: Re: Re: Definition mixins
I'm having a little trouble parsing your proposed syntax. Can you formalize it a bit better? Am I write in guessing that it's more like sugar around bind and composition?

Like, what's going on here?
  mixin obj, mixinFunc1 as method1: privateState, privateStateObj;

I posted a link to a more formal proposal in one of the previous messages:
I updated the syntax in the meantime as indeed this initial one looks confusing. So, instead, it is:

mixin obj: mixinFunc1, mixinFunc2 as method2: privateState1, privateState2;

or you could write it like this:

mixin obj:
    mixinFunc2 as method2:
        privateState1, privateState2;

For the semantics, please see the example in the github spec and the semantics section:

I guess I'm wondering why this would be a part of the language and not just helper functions and a library? Maybe it'd be helpful to represent your chess example using your proposed syntax...?

The most difficult part of implementing it as a library is managing the mix objects that are passed to the mixin function providers. For instance:

class Context1 {
  #privateState = {x: 100};

  mixin this:

  mixin on this: mixinFunc3;

  method() {
    /* ... */

If mixinFunc1, mixinFunc2 come from the same module/script then they share the mix object, so that mixinFunc1 can call mixinFunc2. If mixinFunc3 comes from a different module, then it mustn't have access to the other mixin functions. (Of course, if mixinFunc1 and mixinFunc2 become public methods of the object, for instance if the `mixin on` syntax was used, then mixinFunc3 would have access to them since it has access to the context object.) You could provide an API to mix in functions that come from different places (of course in this case you would need to be more aware about where they come from, which in some cases might be a nuisance), and the API could create the mix object and pass it. But what if the state you want to share with mixinFunc1 is different from the one you share with mixinFunc2? You have to create the mix object yourself and that can get ugly. The way the proposal solves this is by using the [[ScriptOrModule]] slot that functions have.
Some questions (that may be moot once I actually understand your syntax):
* How does it actually prevent colliding names?

You pick only the functions you're interested in. If two mixin function provider expressions resolve to the same identifier name then you can avoid conflicts by using the `as` syntax to give a custom name to the functions. You could benefit from early errors semantics to get an error if you forget to do that.
* How does it interact with closures?

The way any regular objects and functions interact with closures, because indeed it's largely just syntactic sugar.
* How does it prevent mixins from colliding over shared state?

You choose what state you share with any of the mixin functions:

function mixinProvider1(obj, mix, state) { return () => {}; }
function mixinProvider2(obj, mix, state1, state2) { return () => {}; }

class Class {
  #privateState1 = {};
  #privateState2 = {};

  mixin this: mixinProvider1: this.#privateState1;
  mixin this: mixinProvider2: this.#privateState1, this.#privateState2;

If you think about all the possible scenarios you will observe that standard syntax is much simpler than an API. Note that I also imagined a second version for the semantics that you can find in the github spec.

es-discuss mailing list
[hidden email]