Luke Scott (2015-02-12T21:07:38.000Z)
I know what you’re going for, and I had this in my initial implementation. The issue then becomes:

If Trait2 mixes in Trait1, does the init method get replaced? Traits are about inserting functionality, not about inheritance. Example:

trait Trait1 {
    init() {
          // init Trait1
    }
}

trait Trait2 {
    mixin Trait1;

    init() {
        // init Trait 2
    }
}

class Foo {
    mixin Trait2;

    constructor() {
        // do Foo stuff...
    }
}

So either init is special and the call order is Trait1.init() Trait2.init() (while other methods get replaced) or Trait2.init() replaces the Trait1.init(). Also since traits are not classes, they cannot call super. You also are defying the call stack because trait initializers “just happen” internally. There is no trail to step through, unlike classes which leaves a trail of breadcrumbs with super() calls.

This version is actually easy to follow:

trait Trait1 {
    initTrait1() {
          // init Trait1
    }
}

trait Trait2 {
    mixin Trait1;

    initTrait2() {
        this.initTrait1();
        // init Trait 2
    }
}

class Foo {
    mixin Trait2;

    constructor() {
        this.initTrait2();
        // do Foo stuff...
    }
}

True, each class has to call the custom init methods. But it still addresses 95% of the problem: Adding in common functionality that doesn’t fit in classical inheritance. Also since some traits may expect to be mixed in to a subclass of a certain base, it allows you to call super before the trait initializers, and that’s something you already have to do in your local constructor, so initializing traits in the same way makes sense.

The only thing extra beyond copying implementation into a class or another trait is keeping track of what traits have been mixed in for a “hasTrait” check. This isn't necessarily required as you can easily check for a method you want to call, but it does allow you to make sure that the method belongs to trait and check once for a group of methods.

(This is my ES6 implementation of traits that I’m using now: https://gist.github.com/lukescott/36453a75c39c539f5c7d <https://gist.github.com/lukescott/36453a75c39c539f5c7d>)

> On Feb 12, 2015, at 12:47 PM, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:
> 
> Luke, forgot one detail: you do not explicitly initialize traits, these are initialized if these have an `init` or `initialize` method defined, and before the constructor is executed. So, using you example code:
> 
> ```js
> 
> trait Trait1 {
>         initt() {
>                 this.trait1Data = {what:'ever'};
>        }
> }
> 
> class Trait1 {
>         mixin Trait1;
> 
>         constructor() {
>             console.log(this.trait1Data);
>             // {what:'ever'}
>         }
> }
> 
> 
> ```
> 
> That makes them really portable, the class is instantly aware of them since it used them as mixin, but traits are fully independent.
> 
> Do you need a lazy trait? Then you can expose an explicit method to set-it-up and invoke it whenever you want in your constructor.
> 
> Does any of this make sense? It works already in some case of mine :-)
> 
> 
> 
> On Thu, Feb 12, 2015 at 9:42 PM, Andrea Giammarchi <andrea.giammarchi at gmail.com <mailto:andrea.giammarchi at gmail.com>> wrote:
> Luke, answering in order:
> 
> 1. defining order, first come, first serve ... same as everything else on daily usage (events, Array of callbacks, etc)
> 
> 2. You do not ever pass parameter to them, parameters are constructors matters, traits should be independent and unaware of constructors arguments otherwise you loose portability.
> A trait should be able to work and enrich any sort of class, not just some specific one it has no notion about.
> 
> 3. before everything else, since these should be stand-alone behaviors unrelated with constructors
> 
> All marked as IMO, of course :-)
> 
> 
> On Thu, Feb 12, 2015 at 9:33 PM, Luke Scott <luke at cywh.com <mailto:luke at cywh.com>> wrote:
> 
> > On Feb 12, 2015, at 12:11 PM, Domenic Denicola <d at domenic.me <mailto:d at domenic.me>> wrote:
> >
> > From: es-discuss [mailto:es-discuss-bounces at mozilla.org <mailto:es-discuss-bounces at mozilla.org>] On Behalf Of Benjamin Gruenbaum
> >
> >> We have `Object.assign` that works fantastically for most classic trait use cases.
> >
> > Well, actually, it works extremely poorly. The old (now dead or deferred) `Object.mixin`, once called `Object.define`, is a better fit. But it still fails to account for a couple things, off the top of my head:
> >
> > - Being able to add custom initialization logic to the class constructor when "mixing in" a trait. You can construct a custom protocol around this, but (a) that means the class you're mixing in to needs to be aware of the protocol; (b) everyone needs to agree on a protocol across the ecosystem.
> > - Pretty much anything to do with private state doesn't work anymore.
> 
> The biggest issues of trait initializers are (constructors) are:
> 
> - What order do you call them in.
> - How do you pass in parameters into them.
> - They would need to be called by the class constructor. Does this happen at the beginning or end?
> 
> I would argue that traits should not have initializers. It’s much easier to do something like this:
> 
> trait Trait1 {
>         initTrait1() {
>                 // this is a regular method
>                 // init trait here
>        }
> }
> 
> class Trait1 {
>         mixin Trait1;
> 
>         constructor() {
>                 // do work here…
>                 this.initTrait1()
>                 // do more work here...
>         }
> }
> 
> This kind of pattern makes initializing traits more intentional and leaves out any assumptions of what the correct order would be. And not all traits need initializers, so it leaves out a lot of complexity.
> 
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150212/b364acd4/attachment-0001.html>
d at domenic.me (2015-02-17T20:26:32.201Z)
I know what you’re going for, and I had this in my initial implementation. The issue then becomes:

If Trait2 mixes in Trait1, does the init method get replaced? Traits are about inserting functionality, not about inheritance. Example:

```js
trait Trait1 {
    init() {
          // init Trait1
    }
}

trait Trait2 {
    mixin Trait1;

    init() {
        // init Trait 2
    }
}

class Foo {
    mixin Trait2;

    constructor() {
        // do Foo stuff...
    }
}
```

So either init is special and the call order is Trait1.init() Trait2.init() (while other methods get replaced) or Trait2.init() replaces the Trait1.init(). Also since traits are not classes, they cannot call super. You also are defying the call stack because trait initializers “just happen” internally. There is no trail to step through, unlike classes which leaves a trail of breadcrumbs with super() calls.

This version is actually easy to follow:

```js
trait Trait1 {
    initTrait1() {
          // init Trait1
    }
}

trait Trait2 {
    mixin Trait1;

    initTrait2() {
        this.initTrait1();
        // init Trait 2
    }
}

class Foo {
    mixin Trait2;

    constructor() {
        this.initTrait2();
        // do Foo stuff...
    }
}
```

True, each class has to call the custom init methods. But it still addresses 95% of the problem: Adding in common functionality that doesn’t fit in classical inheritance. Also since some traits may expect to be mixed in to a subclass of a certain base, it allows you to call super before the trait initializers, and that’s something you already have to do in your local constructor, so initializing traits in the same way makes sense.

The only thing extra beyond copying implementation into a class or another trait is keeping track of what traits have been mixed in for a “hasTrait” check. This isn't necessarily required as you can easily check for a method you want to call, but it does allow you to make sure that the method belongs to trait and check once for a group of methods.

(This is my ES6 implementation of traits that I’m using now: https://gist.github.com/lukescott/36453a75c39c539f5c7d)