Andrea Giammarchi (2015-02-13T08:40:38.000Z)
It looks like we agree traits are **not** classes so that classes should
not be used or accepted as traits ... which is already an answer to my
initial question.

Other "problems"

init is a special case, as constructor is. You don't need a constructor to
create an instance, you might not need to initialize a trait in order to be
used.

However, trait brings functionality, and this should be consistent. If a
class forgets to initialize a trait this should work regardless. If a class
does not need a constructor, traits should be usable/initialized
automatically regardless.

This is the implicit nature of my proposed `init` . To go your way,
initTrait1() as lazy, explicit method you can **always** do that.

If a trait requires some specific info during initialization, you can
always use `this.initTrait1(info)` inside any class method, but that's
something different from the initial, optional, setup such trait might
need, a setup that, if present, will be granted inside the implicit `init`

What happens inside is also not a class responsibility, class simply has
enriched prototype with methods, when that init should occur is not
necessarily a class matter while those methods should instead work ASAP. An
implicit initializer covers already 100% of cases, it can be absent and go
lazy initializer any time.


Last question: would an init override another init? Well, using as little
as possible stand-alone logic to compose traits, I haven't personally found
a case when Trait2 mixins Trait1 but I believe that's how I'd go

```js
trait Trait2 {
  mixin Trait1;
  init() {
    Trait1.init.call(this);
    this.trait2Data = {any:'thing'};
  }
}
```

init is transparent once mixed in, but reachable regardless explicitly.
Same as it is for constructor, nothing new to learn here, we are used to
`OtherClass.call(this)` now simplified via `super.constructor()`


Last bit of info: all this works already in es-class with traits specified
as objects, here more examples:
https://github.com/WebReflection/es-class/blob/master/FEATURES.md#with

Best Regards




On Thu, Feb 12, 2015 at 10:07 PM, Luke Scott <luke at cywh.com> wrote:

> 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)
>
> 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> 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> wrote:
>>
>>>
>>> > On Feb 12, 2015, at 12:11 PM, Domenic Denicola <d at domenic.me> wrote:
>>> >
>>> > From: es-discuss [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
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>>
>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150213/6501ec16/attachment-0001.html>
d at domenic.me (2015-02-17T20:26:54.845Z)
It looks like we agree traits are **not** classes so that classes should
not be used or accepted as traits ... which is already an answer to my
initial question.

Other "problems"

init is a special case, as constructor is. You don't need a constructor to
create an instance, you might not need to initialize a trait in order to be
used.

However, trait brings functionality, and this should be consistent. If a
class forgets to initialize a trait this should work regardless. If a class
does not need a constructor, traits should be usable/initialized
automatically regardless.

This is the implicit nature of my proposed `init` . To go your way,
initTrait1() as lazy, explicit method you can **always** do that.

If a trait requires some specific info during initialization, you can
always use `this.initTrait1(info)` inside any class method, but that's
something different from the initial, optional, setup such trait might
need, a setup that, if present, will be granted inside the implicit `init`

What happens inside is also not a class responsibility, class simply has
enriched prototype with methods, when that init should occur is not
necessarily a class matter while those methods should instead work ASAP. An
implicit initializer covers already 100% of cases, it can be absent and go
lazy initializer any time.


Last question: would an init override another init? Well, using as little
as possible stand-alone logic to compose traits, I haven't personally found
a case when Trait2 mixins Trait1 but I believe that's how I'd go

```js
trait Trait2 {
  mixin Trait1;
  init() {
    Trait1.init.call(this);
    this.trait2Data = {any:'thing'};
  }
}
```

init is transparent once mixed in, but reachable regardless explicitly.
Same as it is for constructor, nothing new to learn here, we are used to
`OtherClass.call(this)` now simplified via `super.constructor()`


Last bit of info: all this works already in es-class with traits specified
as objects, here more examples:
https://github.com/WebReflection/es-class/blob/master/FEATURES.md#with