For reference, here's the implementation of `multiple()` where multiple constructors calls are possible, using a `callSuperConstructor` helper: https://gist.github.com/trusktr/05b9c763ac70d7086fe3a08c2c4fb4bf
*/#!/*JoePea On Wed, Jul 27, 2016 at 8:16 PM, /#!/JoePea <[email protected]> wrote: > For now, I've settled with writing classes like this: > > ```js > const SomeClassMixin = base => { > class SomeClass extends base { > // ... > } > > return SomeClass > } > > const SomeClass = SomeClassMixin(class{}) > SomeClass.mixin = SomeClassMixin > > export {SomeClass as default} > ``` > > This makes it possible for an end user to import the class and extend from > it like normal: > > ```js > import SomeClass from './SomeClass' > > class OtherClass extends SomeClass { > // ... > } > ``` > > But, it also allows and end user to use it as a mixin: > > ```js > import SomeClass from './SomeClass' > import AnotherClass from './AnotherClass' > > class OtherClass extends SomeClass.mixin(AnotherClass) { > // ... > } > ``` > > This has two main downsides: > > - The class creator has to write the class as a class-factory mixin, then > remember to export the mixin application on a plain `class {}` > - It is not possible to pass specific arguments to the constructors of > each class. > > One of my implementations of `multiple()` *does* allow one to pass > arguments to each constructor. I'll re-visit that when Proxy is supported > in Safari. > > I can't think of any way to make this work using a class helper library, > because those need to create prototype chains, and thus `super` cannot be > modified unless using `eval`, in which case original scope is lost. > > I literally think that a dynamic `super` and/or > `Function.prototype.toMethod` would allow me to implement the ideal > solution, which would have the following benefits: > > I am going to leave this alone for now, and just continue with the > class-factory mixin approach, although that is not my ideal solution. > > Any ideas or suggestions? > > */#!/*JoePea > > On Wed, Jul 27, 2016 at 7:51 PM, /#!/JoePea <[email protected]> wrote: > >> > 1) There are indeed use cases for dynamically configuring the >> HomeObject binding but they are quite specialized >> >> I suppose my case is quite specialized. I am wanting to duplicate the >> prototype chains of ES6 classes, but I have no reliable (afaik) way to make >> the `super` keyword work on copied methods. If I copy the method by >> reference then the `super` keyword is based on the wrong `HomeObject`. If I >> copy the method by getting its the source with `.toString()` followed by >> using `eval` to define the new method on an object initialization, that >> works and `super` will work, but this has problems if the original method >> relied on variables in the outer scope where it was originally defined as >> the copied method will not have access to that scope (f.e. code transpiled >> by Babel may not be able to see the Babel helper functions). >> >> I am trying to implement a function `multiple()` so that I can do >> >> ```js >> class SomeClass { ... } >> class >> OtherClass >> { ... } >> class Foo extends multiple(SomeClass, OtherClass) { ... } >> ``` >> >> and it's proving to be really difficult because I can't configure >> `HomeObject`. The `multiple` function copies the prototype chains of each >> class, then combines them together (when possible, otherwise an error is >> thrown, depending on the native prototypes involved). As mentioned, this >> somewhat works using `eval()` in the implementation, except that copied >> methods don't work if they rely on variables of the outer scope where they >> were originally defined. For example, suppose `SomeClass` in the >> following example was imported from another file, and it depends on Babel >> helpers defined in the original scope where it was imported from: >> >> ```js >> import SomeClass from './somewhere/SomeClass' >> class >> OtherClass >> { ... } >> class Foo extends multiple(SomeClass, OtherClass) { ... } >> ``` >> >> The `multiple()` call will copy the methods of `SomeClass` onto a new >> prototype chain (the methods need new `HomeObjects`), but the new methods >> will fail to reference anything from the original scope where `SomeClass` >> came from. >> >> I need to be able to modify `HomeObject`s without using an `eval()` hack >> in order for my `multiple()` implementation to work 100% as intended. >> >> For now I may need to abandon my effort and use class-factory "mixins" as >> in >> >> ```js >> let SomeMixin = baseClass => class SomeMixin extends baseClass { ... } >> ``` >> >> , but the downside of this is that the classes are not usable as >> standalone classes, so and end-user can't do >> >> ```js >> class Foo extends SomeClass { ... } >> ``` >> >> We are required to do >> >> ```js >> class Foo extends SomeClass(null) { ... } >> ``` >> >> but due to the `null` the class we won't have `Object` methods. We could >> do >> >> ```js >> class Foo extends SomeClass(Object) { ... } >> ``` >> >> , but that is not also ideal as `Object` is not guaranteed to be the >> native Object; `window.Object` could be overridden. >> >> I really want to define plain ES6 classes and use 3rd party plain ES6 >> classes (not class factories). It means that those classes are not limited >> to being used as mixins. >> >> For reference, here's the implementation so far (with the ugly caveats of >> cloning methods with `eval`): >> https://gist.github.com/trusktr/8c515f7bd7436e09a4baa7a63cd7cc37 >> >> I was planning to add caching so that combinations of classes could be >> re-used (similar to what [mixwith.js]( >> https://github.com/justinfagnani/mixwith.js) does to cache mixin >> applications). >> >> > We aren’t going to do anything until there is significant real world >> feedback saying that it really is needed. >> >> Here's that feedback. :D >> >> TLDR, it seems that without flexibility in modifying `[[HomeObject]]` in >> order to control what `super` references, I cannot implement an ideal >> `multiple()`-inheritance helper that I would be able to comfortably suggest >> for use in a production app. I would definitely not recommend the my >> `eval`-based implementation as it will fail in ways that are very >> undesirable and unexpected. >> >> With the limitation of a static `super`, I can't do something simple like >> use `Object.assign` to simply copy some methods from one class' prototype >> onto the class where I need them. That's normal pre-ES6 stuff that has >> worked along with a dynamic `this` since forever, so the change in behavior >> from `this` to `super` doesn't fit with the pre-ES6 language that we are >> previously accustomed to and that we love (I do). ES6+ is >> backwards-incompatible with some pre-ES6 paradigms. >> >> Pleeeease, let's add something like `toMethod`, or make `super` dynamic >> (preferably both). I don't see any downside to having something like >> `Function.prototype.toMethod`, as it is an opt-in type of feature, so it >> won't bring with it performance loss like a dynamic `super` might (I still >> haven't heard conclusive evidence regarding those performance losses). >> >> From what I can imagine, property lookup checks checks the current >> object, then goes to the next prototype and does the same, until finally it >> reaches a prototype where the property is found. Once that object (a >> HomeObject) is found, we know what the `HomeObject` is. It seems very easy >> to call a found method with that found `HomeObject`argument, and when the >> method is called and if it uses `super`, then a similar search will happen >> up the prototype chain until the matching super property is found. The >> second prototype search (the one initiated due to the method using `super`) >> is already a requirement, so, this means that the extra overhead for a >> dynamic `super` stems from simply passing as argument the `HomeObject` of a >> method once the method is found on a prototype chain. A static super means >> that the `[[HomeObject]]` variable is simply defined forever instead of >> being marked in the property-lookup of a method, and that doesn't seem >> like tons of extra overhead. Note that the property lookup is going to >> happen anyways, so why not mark the `HomeObject` during the property lookup >> algorithm? >> >> *Is that really enough overhead to merit a static `super`?* If someone >> can explain it (or link to it), that would be greatly appreciated. >> >> I also think having dynamic `super` (or at least a way to configure it) >> opens up language possibilities that can make interesting things happen >> (for example, my `multiple()`-inheritance implementation would work >> smoothly and instanceof checks would also work thanks to `@@hasInstance`). >> The mere fact that a dynamic or configurable `[[HomeObject]]` would allow >> for the creation of a tool like what I am trying to implement is good >> enough reason to have the feature. Who knows what other awesome ideas >> people will come up with. >> >> */#!/*JoePea >> >> On Sun, Jul 24, 2016 at 7:54 PM, Allen Wirfs-Brock <[email protected] >> > wrote: >> >>> >>> On Jul 24, 2016, at 7:04 PM, /#!/JoePea <[email protected]> wrote: >>> >>> What if there was also something like `Function.prototype.bind` like >>> `Function.prototype.with`, so `someFunc.with(homeObject)` returns a new >>> function who's [[HomeObject]] is the specified `homeObject`. It would be >>> possible to do `someFunc.with(...).bind(...)` to configure both the home >>> object and `this`. >>> >>> >>> This was included in the ES6 drafst for quite awhile. Initially with >>> the name defineMethod and latter as toMethod. But it was eventually >>> decided to remove it. The pros and cons of such a function were >>> extensively discussed with in TC39 over a several year period. For example, >>> see >>> https://github.com/tc39/tc39-notes/blob/master/es6/2014-01/jan-28.md#more-on-tomethod >>> >>> >>> The issues with defineMethod/toMethod are summarized in >>> https://github.com/tc39/tc39-notes/blob/master/es6/2015-03/mixin-proposal.pdf >>> and https://github.com/allenwb/ESideas/blob/master/dcltomethod.md which >>> is a proposal for an alternative way to address the problem. Notes from >>> that discussion are at >>> https://github.com/tc39/tc39-notes/blob/master/es6/2015-03/mar-25.md#6iv-a-declarative-alternative-to-tomethod-allen-wirfs-brock >>> >>> >>> Where it has been left by TC30 is roughly: >>> 1) There are indeed use cases for dynamically configuring the HomeObject >>> binding but they are quite specialized. >>> 2) All of the solution that have been proposed are confusing or error >>> prone. >>> 3) So far, the actual user demand for such a feature is small. >>> 4) We aren’t going to do anything until there is significant real world >>> feedback saying that it really is needed. >>> >>> Allen >>> >> >> >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

