You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It is different because we expans in a class the content of other(s) classes, ie like mixins do, enabling in a certain manner multiple inheritance we don t have in modern languages , we had in first Smalktalk versions.
One example of use :
Imagine you have two react ui components like container and paper.
We could also have a third one which is containerpaper which fuses the features of the two previous ones. Instead of creating this third component, we could inject container capabilities into paper (or the contrary).
I think the same effect could be achieved by having more freedom in the "extend from expression" feature. It is almost possible today with this syntax:
classXextendsMixin<A,B>(){}
And I would very much prefer that syntax over the ...: A; ...: B proposed.
Now, it seems to me that this is impossible in TS 1.7 because when I try that:
the TS compiler complaints that "Base constructor return type 'T & U' is not a class or an interface.".
This is a little sad and if the restriction might be lifted somehow you would have nice Mixins in the langage with a single helper function. Is there (or could there be) a way to say that T and U generics parameters are constrained to classes and interfaces, so T & U is OK for the compiler?
You can make it work today if you accept creating one interface for each of your mixins combinations, like so:
// Your global Mixin helper functionfunctionMixin<Target,Src1,Src2>(a: new()=>Src1,b: new()=>Src2) : new()=>Target{ ... }// Sample mixins you want to useclassDog{bark(){...}}classDuck{quack(){...}}// This is the extra interface that you need, it's empty: just a one-linerinterfaceDoggyDuckextendsMixin1,Mixin2{}// Now you can easily create derived classes classMutantextendsMixin<DoggyDuck,Dog,Duck>(Dog,Duck){ ... }// It works well at compile time and run time!varxavier=newMutant();xavier.bark();xavier.quack();
And I think with TS 1.8 F-Bounded Polymorphism we might get extra safety allowing a constraint that Target extends Src1 & Src2.
Thanks jod for this nice piece of code, nevertheless a little bit tricky :)
Nevertheless, multi inheritance have some drawbacks we must face on like what about same methods defined in the different classes to be "merged", or same instance variables initialized differently? Except these cases, mixins are good means to avoid redefining some components when we need to have a tomato which is either a fruit and a vegetable :)
Personnally, i like the syntactic sugar i proposed :
... : A&B&C
I think the same effect could be achieved by having more freedom in the "extend from expression" feature. It is almost possible today with this syntax:
class X extends Mixin<A,B>() {
}
And I would very much prefer that syntax over the ...: A; ...: B proposed.
Now, it seems to me that this is impossible in TS 1.7 because when I try that:
function Mixin<T,U>(t: new() => T, u: new() => U): new() => T & U { ... }
the TS compiler complaints that "Base constructor return type 'T & U' is not a class or an interface.".
This is a little sad and if the restriction might be lifted somehow you would have nice Mixins in the langage with a single helper function. Is there (or could there be) a way to say that T and U generics parameters are constrained to classes and interfaces, so T & U is OK for the compiler?
You can make it work today if you accept creating one interface for each of your mixins combinations, like so:
// Your global Mixin helper function
function Mixin<Target, Src1, Src2>(a: new() => Src1, b: new() => Src2) : new() => Target { ... }
// Sample mixins you want to use
class Dog {
bark() {...}
}
class Duck {
quack() {...}
}
// This is the extra interface that you need, it's empty: just a one-liner
interface DoggyDuck extends Mixin1, Mixin2 { }
// Now you can easily create derived classes
class Mutant extends Mixin<DoggyDuck, Dog, Duck>(Dog, Duck) { ... }
// It works well at compile time and run time!
var xavier = new Mutant();
xavier.bark();
xavier.quack();
And I think with TS 1.8 F-Bounded Polymorphism we might get extra safety allowing a constraint that Target extends Src1 & Src2.
—
Reply to this email directly or view it on GitHub.
I think the same effect could be achieved by having more freedom in the "extend from expression" feature. It is almost possible today with this syntax:
class X extends Mixin<A,B>() {
}
And I would very much prefer that syntax over the ...: A; ...: B proposed.
Now, it seems to me that this is impossible in TS 1.7 because when I try that:
function Mixin<T,U>(t: new() => T, u: new() => U): new() => T & U { ... }
the TS compiler complaints that "Base constructor return type 'T & U' is not a class or an interface.".
This is a little sad and if the restriction might be lifted somehow you would have nice Mixins in the langage with a single helper function. Is there (or could there be) a way to say that T and U generics parameters are constrained to classes and interfaces, so T & U is OK for the compiler?
You can make it work today if you accept creating one interface for each of your mixins combinations, like so:
// Your global Mixin helper function
function Mixin<Target, Src1, Src2>(a: new() => Src1, b: new() => Src2) : new() => Target { ... }
// Sample mixins you want to use
class Dog {
bark() {...}
}
class Duck {
quack() {...}
}
// This is the extra interface that you need, it's empty: just a one-liner
interface DoggyDuck extends Mixin1, Mixin2 { }
// Now you can easily create derived classes
class Mutant extends Mixin<DoggyDuck, Dog, Duck>(Dog, Duck) { ... }
// It works well at compile time and run time!
var xavier = new Mutant();
xavier.bark();
xavier.quack();
And I think with TS 1.8 F-Bounded Polymorphism we might get extra safety allowing a constraint that Target extends Src1 & Src2.
—
Reply to this email directly or view it on GitHub.
xmehaut
I'm pretty sure you can inject your mixins at runtime using decorators, which is a nice syntax for that. But I don't think there is a way to augment the static, compile-time type with decorators, which is a huge drawback: all your mixins have to be handled as any types :(
It is different because we expans in a class the content of other(s) classes, ie like mixins do,
so who is responsible for mixing in the new class at runtime? do you expect the generated code to do this for you? or you will be calling some extends method later on?
if it is the erlieri do not see how generrics pattern can ever be used here, and you should probally look into #2919 instead.
It is different because we expans in a class the content of other(s) classes, ie like mixins do,
so who is responsible for mixing in the new class at runtime? do you expect the generated code to do this for you? or you will be calling some extends method later on?
if it is the erlieri do not see how generrics pattern can ever be used here, and you should probally look into #2919 instead.
—
Reply to this email directly or view it on GitHub.
it is the same purpose , yes, and the syntax is a little bit different
beacuse they refer more to rest desconstructing than to inheritance-like
formalism... It is imprtant in the sense that we don't want to mimic
multinheritance, but we want more a copy-like behavior... For instance, if
we have in one of a mixin a method which has the same signature than the
one of the target class, it won't be copied and not overwrite the one in
place; the same for constructor or instance variables...
Beat me to it, but it works. I initially had a condition for 'constructor', but it works without that condition. It doesn't seem to override the base class one (although the mixin does have a constructor own property).
If you look at the code emitted, in extend, there's object.create(b) which means that the actual constructor should be the right one (the actual constructor is not the prototype property, but the 'private' javascript prototype.
Izhaki I am not sure what you mean by "it works".
Starting with your code I can do this:
letbug=newAnimal();bug['paint']();
This should crash but it does print "paint" in the console. This demonstrates that you have clearly modified Animal.prototype, which is bad.
My original code worked around this by copying all prototypes into a new one (the X class). The only drawback is that the base ctor was not called but this is easily fixable. Here is a better mixin function:
The first argument is considered to be a base class, and hence, its ctor is called.
You can tweak this in various ways: removing Object.assign (I use it for convenience), call all ctors in chain including your mixins (so that your mixins may initialize state), make the function work without a base class at all, etc.
Here's an updated playground that demonstrate this working with a non-trivial base class: Playground
In the interests of not reading this thread in detail if possible -- does the code above solve your use case enough that we can close this as having a sufficient solution in place?
In the interests of not reading this thread in detail if possible -- does the code above solve your use case enough that we can close this as having a sufficient solution in place?
—
Reply to this email directly or view it on GitHub.
Sorry, I missed this... I have used the pattern mentioned in this issue quite extensively and there is one challenge to it (which I don't think the original proposal addressed either, given the following:
classA{foo: string='';}classB{foo(){return'foo';};}interfaceGenericClass<T>{new(...args: any[]): T;}functionmixin<T,U>(target: GenericClass<T>,source: GenericClass<U>): GenericClass<T&U>{return;}constC=mixin(A,B);constc=newC();c.foo;// is of type string & (() => string)
You run into issues when you have members that conflict.
As far as the original proposal, I would prefer the #3870 as I think that type of operations that we are talking about could be handled better that way something like:
functionmixin<T, ...U>(target: (new()=>T), ...mixins: (new()=>U)[]): (new()=>T& ...U){// do mixin}
There are some other considerations too about that discussed in #3870... should ...U be A&B&C... or should it be A|B|C..., etc...
Carsten Klein (@silkentrance) run-time decorators don't modify the type information. class MouseyCatDog would be a class without any properties at design time, though it could have the proper run-time structure, but not having the right design time structure is essentially useless (and dangerous).
Kitson Kelly (@kitsonk) Basically, what you are asking for is not a mixin concept but, simply put, a multiple inheritance concept where the first class inherited from would be the actual super prototype and any other classes following that would be treated as mixins, e.g.
class Foo extends Bar, Car, Tar
{}
The generated/augmented constructor would then call upon first Bar.apply(), then Car and last but not least Tar.
If this be true, then instanceof Car and instanceof Tar should not fail. Again, here the transpiler could replace uses of instanceof by a custom implementation that will return true for all mixins and theirs and the super class' prototype chain.
As such, and during runtime, the generated class Foo would need some extra annotations, e.g.
Activity
mhegazy commentedon Jan 16, 2016
how is that diffrent from:
xmehaut commentedon Jan 16, 2016
It is different because we expans in a class the content of other(s) classes, ie like mixins do, enabling in a certain manner multiple inheritance we don t have in modern languages , we had in first Smalktalk versions.
Envoyé de mon iPhone
xmehaut commentedon Jan 16, 2016
One example of use :
Imagine you have two react ui components like container and paper.
We could also have a third one which is containerpaper which fuses the features of the two previous ones. Instead of creating this third component, we could inject container capabilities into paper (or the contrary).
Envoyé de mon iPhone
jods4 commentedon Jan 18, 2016
I think the same effect could be achieved by having more freedom in the "extend from expression" feature. It is almost possible today with this syntax:
And I would very much prefer that syntax over the
...: A; ...: Bproposed.Now, it seems to me that this is impossible in TS 1.7 because when I try that:
the TS compiler complaints that "Base constructor return type 'T & U' is not a class or an interface.".
This is a little sad and if the restriction might be lifted somehow you would have nice Mixins in the langage with a single helper function. Is there (or could there be) a way to say that
TandUgenerics parameters are constrained to classes and interfaces, soT & Uis OK for the compiler?You can make it work today if you accept creating one interface for each of your mixins combinations, like so:
And I think with TS 1.8 F-Bounded Polymorphism we might get extra safety allowing a constraint that
Target extends Src1 & Src2.xmehaut commentedon Jan 19, 2016
Thanks jod for this nice piece of code, nevertheless a little bit tricky :)
Nevertheless, multi inheritance have some drawbacks we must face on like what about same methods defined in the different classes to be "merged", or same instance variables initialized differently? Except these cases, mixins are good means to avoid redefining some components when we need to have a tomato which is either a fruit and a vegetable :)
Personnally, i like the syntactic sugar i proposed :
... : A&B&C
It is quite concise and auto explained
Envoyé de mon iPhone
xmehaut commentedon Jan 19, 2016
Hi jods
Is there a means to do the same by using decorators to inject the mixin classes into the current one?
Envoyé de mon iPhone
jods4 commentedon Jan 19, 2016
xmehaut
I'm pretty sure you can inject your mixins at runtime using decorators, which is a nice syntax for that.
But I don't think there is a way to augment the static, compile-time type with decorators, which is a huge drawback: all your mixins have to be handled as
anytypes :(mhegazy commentedon Jan 19, 2016
so who is responsible for mixing in the new class at runtime? do you expect the generated code to do this for you? or you will be calling some
extendsmethod later on?if it is the erlieri do not see how generrics pattern can ever be used here, and you should probally look into #2919 instead.
xmehaut commentedon Jan 19, 2016
The generics into the example are not related with the expansion. We could without by just writing ... : type1 & type 2
Yes i would intend that the expansion would generate the js mixin code
Envoyé de mon iPhone
mhegazy commentedon Jan 19, 2016
how is this different from #2919 or #311? is it just the syntax?
xmehaut commentedon Jan 19, 2016
it is the same purpose , yes, and the syntax is a little bit different
beacuse they refer more to rest desconstructing than to inheritance-like
formalism... It is imprtant in the sense that we don't want to mimic
multinheritance, but we want more a copy-like behavior... For instance, if
we have in one of a mixin a method which has the same signature than the
one of the target class, it won't be copied and not overwrite the one in
place; the same for constructor or instance variables...
2016-01-19 20:34 GMT+01:00 Mohamed Hegazy notifications@github.com:
Izhaki commentedon Jan 20, 2016
jods (@jods4)
Can you provide a working example on http://www.typescriptlang.org/Playground ?
jods4 commentedon Jan 20, 2016
Izhaki Something along those lines. Note that I simplified the Mixin signature a bit.
Playground
1 remaining item
xmehaut commentedon Jan 20, 2016
very nice!
2016-01-20 16:25 GMT+01:00 Izhaki notifications@github.com:
jods4 commentedon Jan 20, 2016
Izhaki No problem with the changes, my code was a quick proof of concept ;)
Just one point:
baseClass.prototype[ name ] = mixin.prototype[ name ]Aren't you mutating your base classe ctor?
I think you need to create a new intermediate base class (like I did with
X).Izhaki commentedon Jan 20, 2016
jods (@jods4)
Beat me to it, but it works. I initially had a condition for 'constructor', but it works without that condition. It doesn't seem to override the base class one (although the mixin does have a constructor own property).
If you look at the code emitted, in extend, there's
object.create(b)which means that the actual constructor should be the right one (the actual constructor is not the prototype property, but the 'private' javascript prototype.jods4 commentedon Jan 20, 2016
Izhaki I am not sure what you mean by "it works".
Starting with your code I can do this:
This should crash but it does print "paint" in the console. This demonstrates that you have clearly modified
Animal.prototype, which is bad.My original code worked around this by copying all prototypes into a new one (the
Xclass). The only drawback is that the base ctor was not called but this is easily fixable. Here is a better mixin function:The first argument is considered to be a base class, and hence, its ctor is called.
You can tweak this in various ways: removing
Object.assign(I use it for convenience), call all ctors in chain including your mixins (so that your mixins may initialize state), make the function work without a base class at all, etc.Here's an updated playground that demonstrate this working with a non-trivial base class:
Playground
Izhaki commentedon Jan 20, 2016
jods (@jods4), well spotted. This is brilliant stuff.
RyanCavanaugh commentedon Jan 21, 2016
In the interests of not reading this thread in detail if possible -- does the code above solve your use case enough that we can close this as having a sufficient solution in place?
xmehaut commentedon Jan 21, 2016
It is ok for me, even if i would prefer a syntactic sugar in typescript above this solution.
Best regards
Envoyé de mon iPhone
kitsonk commentedon Jan 23, 2016
Sorry, I missed this... I have used the pattern mentioned in this issue quite extensively and there is one challenge to it (which I don't think the original proposal addressed either, given the following:
You run into issues when you have members that conflict.
As far as the original proposal, I would prefer the #3870 as I think that type of operations that we are talking about could be handled better that way something like:
There are some other considerations too about that discussed in #3870... should
...UbeA&B&C...or should it beA|B|C..., etc...iBasit commentedon Feb 14, 2016
A&B&C...makes more since thenA|B|C...silkentrance commentedon Mar 4, 2016
Why don't you just use a mixin decorator?
This would not require any change to the language at all.
kitsonk commentedon Mar 4, 2016
Carsten Klein (@silkentrance) run-time decorators don't modify the type information.
class MouseyCatDogwould be a class without any properties at design time, though it could have the proper run-time structure, but not having the right design time structure is essentially useless (and dangerous).silkentrance commentedon Mar 4, 2016
Kitson Kelly (@kitsonk) Basically, what you are asking for is not a mixin concept but, simply put, a multiple inheritance concept where the first class inherited from would be the actual super prototype and any other classes following that would be treated as mixins, e.g.
The generated/augmented constructor would then call upon first Bar.apply(), then Car and last but not least Tar.
If this be true, then
instanceof Carandinstanceof Tarshould not fail. Again, here the transpiler could replace uses ofinstanceofby a custom implementation that will return true for all mixins and theirs and the super class' prototype chain.As such, and during runtime, the generated class Foo would need some extra annotations, e.g.
Otherwise we talk about IDEs here and their use of the AST produced by the typescript ast generator.
And, according to your last comment on #2900, the use of extraneous files.
ahejlsberg commentedon Jan 30, 2017
Closing as mixin classes are now supported with #13743.