I read that React mixins article, and I think those are all good points, but in my case I am after multiple-inheritance, which seems to be a good use-case for mixins (as in that article by Justin Fagnani above), a somewhat different use case than the ones in the React article.
I'm attempting to take a mixin-based approach (with ideas inspired from [mixwith.js](https://github.com/justinfagnani/mixwith.js/issues/new)), who's outer API usage looks like this: ```js import multiple from 'somewhere-yet-to-exist' class Foo {} class Bar extends Foo {} (new Bar) instanceof Foo // true let Klass = multiple(Foo) // take note! class Baz extends Klass {} (new Baz) instanceof Klass // true (new Baz) instanceof Foo // true (is this possible?) class Lorem {} let Clazz = multiple(Foo, Lorem) // take note! class Ipsum extends Clazz {} (new Ipsum) instanceof Clazz // true (new Ipsum) instanceof Foo // true (is this possible?) (new Ipsum) instanceof Lorem // true (is this possible?) ``` Or, in other words, I hope it's possible to make this possible: ```js import multiple from 'somewhere-yet-to-exist' class Foo {} class Lorem {} // --- extend one class: class Something extends Lorem {} // --- extend more than one class: class SomethingElse extends multiple(Foo, Lorem) {} // --- instanceof should work: (new Something) instanceof Lorem // true (new SomethingElse) instanceof Lorem // true ``` I suppose I'll know if it's possible after I try implementing it. :D */#!/*JoePea On Wed, Jul 13, 2016 at 2:25 PM, Andrea Giammarchi < [email protected]> wrote: > to be fair, that post is about problems with React architecture or the way > they use mixins, not necessarily with mixins in general. > > All points are highly subjective and not so difficult to avoid. > > ```js > // do not invoke within mixin methods > // stuff that doesn't belong to the mixin > // so no `renderHeader` case or issue > var myMixin = { > doSomething(some, thing) { > // avoid problems with refactoring or name clashing > myMixin.doStuff.apply(this, arguments); > }, > doStuff(some, stuff) { > // do something useful with this mixin > // never call something not available > } > }; > > // compose and use mixins without problems > class MyClass extends(myMixin) { > // no problems on name clashing > // override and use explicit methods > doSomething() { > myMixin.doSomething.call(this, 'some', 123); > // eventually: myOtherMixin.doSomething.call(this, 'other'); > } > } > > // same logic to merge mixins, either an object or a class to extend later > on > > // the third point is still a very React-centric issue as it's presented > in there > ``` > > Of course, borrowing method with some sugar would be a huge help so that > > ```js > var myMixin = { > doSomething(some, thing) { > this::myMixin.doStuff(some, thing); > }, > doStuff(some, stuff) { > } > }; > > class MyClass extends(myMixin) { > doSomething() { > this::myMixin.doSomething('some', 123); > } > } > > ``` > > But IIRC that proposal has been put on hold, it's on stage 0 or not sure > whatever happened. > > If it was usable maybe, the React post, would have been a different story > (like ... "How to avoid mixins problems") > > Best Regards > > > > > > On Wed, Jul 13, 2016 at 9:41 PM, Jordan Harband <[email protected]> wrote: > >> >> <https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html> >> <https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html> >> https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html >> may also be a helpful read. >> >> (fwiw, any Symbol to modify property lookup would not likely ship before >> Proxy was available, so "use Proxy" is a pretty solid suggestion for this) >> >> On Wed, Jul 13, 2016 at 1:04 PM, /#!/JoePea <[email protected]> wrote: >> >>> Thanks kdex. >>> >>> In one of my cases, `A` extends `B` extends `C` just so that `A` can >>> have characteristics of both `B` and `C`, but it doesn't actually make >>> sense for `B` to extend `C` because `B` is not a more specific form of `C` >>> -- `B` and `C` are completely unrelated classes; I'm extending `B` from `C` >>> just for `A` to have both sets of characteristics. >>> >>> How might decorators be used instead? >>> >>> I found some good reading: >>> >>> - >>> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Mix-ins >>> - >>> http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/ >>> >>> I am currently reading to get ideas on what I might do, but would love >>> suggestions if you have any. >>> >>> */#!/*JoePea >>> >>> On Wed, Jul 13, 2016 at 3:00 AM, kdex <[email protected]> wrote: >>> >>>> Callable class constructors [1] have been discussed at some point. >>>> They've been withdrawn [2] in favor of decorators [3], though. >>>> >>>> [1] >>>> https://github.com/tc39/ecma262/blob/master/workingdocs/callconstructor.md >>>> [2] >>>> https://github.com/tc39/proposals/blob/master/inactive-proposals.md#inactive-proposals >>>> [3] >>>> https://github.com/wycats/javascript-decorators/blob/master/README.md >>>> >>>> On Wednesday, July 13, 2016 2:24:10 AM CEST /#!/JoePea wrote: >>>> > Oops, I forgot that ES6 classes can't be called using the >>>> > `SomeClass.call(...)` form. Is there a workaround for that so that my >>>> > constructor can call all of them (besides downgrading to ES5 classes)? >>>> > >>>> > ```js >>>> > class Foo extends new MultiClass(One, Two) { >>>> > constructor(...args) { >>>> > One.call(this, ...args) >>>> > // Error, not allowed >>>> > >>>> > >>>> > Two >>>> > .call(this, ...args) // >>>> > Error >>>> > , not allowed >>>> > >>>> > } >>>> > } >>>> > ``` >>>> > >>>> > */#!/*JoePea >>>> > >>>> > On Wed, Jul 13, 2016 at 1:49 AM, /#!/JoePea <[email protected]> wrote: >>>> > >>>> > > Thanks guys, Proxy is the one, but not supported natively enough yet >>>> > > unfortunately. >>>> > > >>>> > > Here is the ES5 solution I came up with, which creates "proxy" >>>> methods on >>>> > > the "multiPrototype" of the new MultiClass: >>>> > > >>>> > > ```js >>>> > > class MultiClass { >>>> > > constructor(...constructors) { >>>> > > let constructorName = '' >>>> > > let multiPrototype = {} >>>> > > >>>> > > console.log(' -- Creating new MultiClass.') >>>> > > >>>> > > for (let i=0, l=constructors.length; i<l; i+=1) { >>>> > > const constructor = constructors[i] >>>> > > >>>> > > constructorName += constructor.name + (i == l-1 ? '' : >>>> '+') >>>> > > // f.e. SomeClass_OtherClass_FooBar >>>> > > >>>> > > let props = >>>> > > >>>> SimplePropertyRetriever.getOwnAndPrototypeEnumerablesAndNonenumerables(constructor.prototype) >>>> > > for (let prop of props) { >>>> > > multiPrototype[prop] = constructor.prototype[prop] >>>> > > console.log(' --- prop', prop) >>>> > > } >>>> > > } >>>> > > >>>> > > // temporary object to store the new MultiClass constructor, >>>> > > because >>>> > > // using an object allows us to programmatically assign a >>>> name to >>>> > > the >>>> > > // function, which we otherwise cannot do without eval(). >>>> > > let tmp = { >>>> > > >>>> > > // This new constructor doesn't do much, just has all >>>> the given >>>> > > // constructor prototypes mixed in to it's own >>>> prototype. Be >>>> > > sure to >>>> > > // call the each constructor manually in the class that >>>> > > extends this >>>> > > // new MultiClass. >>>> > > [constructorName]() {} >>>> > > >>>> > > } >>>> > > >>>> > > tmp[constructorName].prototype = multiPrototype >>>> > > >>>> > > return tmp[constructorName] >>>> > > } >>>> > > } >>>> > > ``` >>>> > > >>>> > > Where `SimplePropertyRetriever` is taken from the MDN article >>>> > > [Enumerability and ownership of properties]( >>>> > > >>>> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties#Obtaining_properties_by_enumerabilityownership >>>> > > ). >>>> > > >>>> > > Example usage: >>>> > > >>>> > > ```js >>>> > > class One { >>>> > > foo() {console.log('foo')} >>>> > > } >>>> > > >>>> > > class Two { >>>> > > constructor() {/* ... */} >>>> > > bar() {console.log('bar')} >>>> > > } >>>> > > >>>> > > class Three extends Two { >>>> > > constructor(...args) { >>>> > > super(...args) >>>> > > // ... >>>> > > } >>>> > > baz() {console.log('baz')} >>>> > > } >>>> > > >>>> > > class FooBar extends new MultiClass(Three, One) { >>>> > > constructor(...args) { >>>> > > super() // needed, although does nothing. >>>> > > >>>> > > // call each constructor. >>>> > > One.call(this, ...args) >>>> > > Three.call(this, ...args) >>>> > > } >>>> > > oh() {console.log('oh')} >>>> > > yeah() {console.log('yeah')} >>>> > > } >>>> > > >>>> > > let f = new FooBar >>>> > > >>>> > > f.foo() >>>> > > f.bar() >>>> > > f.baz() >>>> > > f.oh() >>>> > > f.yeah() >>>> > > ``` >>>> > > >>>> > > Any ideas on how else to do it? >>>> > > >>>> > > */#!/*JoePea >>>> > > >>>> > > On Tue, Jul 12, 2016 at 1:52 AM, Claude Pache < >>>> [email protected]> >>>> > > wrote: >>>> > > >>>> > >> >>>> > >> Le 12 juil. 2016 à 02:45, /#!/JoePea <[email protected]> a écrit : >>>> > >> >>>> > >> Does one exist? I'm imagining an implementation for >>>> > >> >>>> > >> ``` >>>> > >> class Node extends new MultiClass(ImperativeBase, Transformable) { >>>> > >> } >>>> > >> ``` >>>> > >> >>>> > >> >>>> > >> I think that Proxy is the tool for that purpose. >>>> > >> >>>> > >> How a symbol would work here, since you need a property lookup in >>>> order >>>> > >> to find that symbol? >>>> > >> >>>> > >> —Claude >>>> > >> >>>> > > >>>> > > >>>> > >>>> >>> >>> >>> _______________________________________________ >>> es-discuss mailing list >>> [email protected] >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >> >> _______________________________________________ >> es-discuss mailing list >> [email protected] >> https://mail.mozilla.org/listinfo/es-discuss >> >> >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

