Symbol for modifying property lookup?
/#!/JoePea
joe at trusktr.io
Mon Jul 18 04:55:06 UTC 2016
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 <
andrea.giammarchi at gmail.com> 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 <ljharb at gmail.com> 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 <joe at trusktr.io> 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 <kdex at kdex.de> 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 <joe at trusktr.io> 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 <
>>>> claude.pache at gmail.com>
>>>> > > wrote:
>>>> > >
>>>> > >>
>>>> > >> Le 12 juil. 2016 à 02:45, /#!/JoePea <joe at trusktr.io> 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
>>> 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/20160717/7c0e3082/attachment-0001.html>
More information about the es-discuss
mailing list