Symbol for modifying property lookup?
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?
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:
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.
Example usage:
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?
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)?
class Foo extends new MultiClass(One, Two) {
constructor(...args) {
One.call(this, ...args)
// Error, not allowed
Two
.call(this, ...args) //
Error
, not allowed
}
}
Callable class constructors [1] have been discussed at some point. They've been withdrawn [2] in favor of decorators [3], though.
[1] tc39/ecma262/blob/master/workingdocs/callconstructor.md [2] tc39/proposals/blob/master/inactive-proposals.md#inactive-proposals [3] wycats/javascript-decorators/blob/master/README.md
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:
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Mix-ins
I am currently reading to get ideas on what I might do, but would love suggestions if you have any.
facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html, facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html
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)
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.
// 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
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
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), who's outer API usage looks like this:
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:
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
I did an implementation of mix-ins, traits and interfaces. It’s far to be perfect and it doesn’t integrate with the “class” construct, but if you are interested, my project is named “doodad-js” and you can download it from npm.
From: /#!/JoePea [mailto:joe at trusktr.io] Sent: Monday, July 18, 2016 12:55 AM To: Andrea Giammarchi <andrea.giammarchi at gmail.com>
Cc: es-discuss <es-discuss at mozilla.org>
Subject: Re: Symbol for modifying property lookup?
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), who's outer API usage looks like this:
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:
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 <mailto: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.
// 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
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
On Wed, Jul 13, 2016 at 9:41 PM, Jordan Harband <ljharb at gmail.com <mailto:ljharb at gmail.com> > wrote:
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 <mailto: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:
-
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Mix-ins
-
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 <mailto: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] tc39/ecma262/blob/master/workingdocs/callconstructor.md [2] tc39/proposals/blob/master/inactive-proposals.md#inactive-proposals [3] wycats/javascript-decorators/blob/master/README.md
Does one exist? I'm imagining an implementation for