Thread overview | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 30, 2004 COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Attachments:
| I would like to proposed the following specification for Mixins be included as part of Version 1.0 D Programming Language specification. All comments are welcomed. MIXINS SPECIFICATION Version 0.1 Introduction What are mixins ? A mixin is a class-like entity whose methods/fields are mixed-in to the mixing class just as if the author of that class had written them manually. As Matthew so neatly put it (see http://www.digitalmars.com/drn-bin/wwwnews?D/28348 ) Why do we need them ? The rational for Mixins is quite compelling... One of the greatest shortcomings of the C++ language from a Object Oriented perspective, is that there is no language support for Aggregated Objects. As such, Aggregation has to be performed programatically, often (incorrectly) using the inheritance mechanism as a coding shortcut. By including language support we provide a direct correlation between OOD using modeling techniques like UML, and OOP. Background Please read the following; http://www.digitalmars.com/drn-bin/wwwnews?D/28455 http://www.digitalmars.com/drn-bin/wwwnews?D/28511 http://www.digitalmars.com/drn-bin/wwwnews?D/28553 Lexical I propose that we use one of the two remaining (common) symbols, i.e. # and @ as well as the keyword mixin. For this document we'll use # as the mixin symbol Syntax There are a number of syntax alternatives that could be incorporated. Alternative A: class <identifier> [: <inherited-class>] [# <aggregated-class> <local-identifier>]* For example; class Lamp : Light # Body cBody # Switch cSwitch # Globe cGlobe # PowerCord cPowerCord { this() { super(); cBody(); // Body construction cGlobe(); // Globe construction cPowerCord(); // PowerCord construction cSwitch(cGlobe,cPowerCord); // Switch construction } }; Alternative B: class <identifier> [: <inherited-class>] [# <aggregated-class> <local-identifier> [, <aggregated-class> <local-identifier>]*] For example; class Lamp : Light # Body cBody , Switch cSwitch , Globe cGlobe , PowerCord cPowerCord { this() { super(); cBody(); // Body construction cGlobe(); // Globe construction cPowerCord(); // PowerCord construction cSwitch(cGlobe,cPowerCord); // Switch construction } }; Semantics The rules for Mixin variables should be the same as class member declarations, except Mixins allow the interfaces of the aggregated class to be included as part of the mixing class. This fact means that it is possible to have multiple versions of the same member name within a mixing class. I propose a simple precedence rule, where the member defined in the class overrides those defined in the aggregated class, and those in the aggregated classes are assigned according to the order they are declared. If this was to take place, a compiler warning message stating "that member X of aggregated class A is taking precedence over that in aggregated class B" should be displayed in the error log. Note: there are probably other things that will need to be considered here ! Conclusion Mixins permit externally declare classes to be used as part of a class, and in so doing provides a real alternative to the Multiple Inheritance option provided for in the C++ language. As such, this relatively insignificant addition to the language should greatly enhance the overall flexibility of the D Programming Language. Comments ! |
April 30, 2004 Re: COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Posted in reply to fred | fred wrote: > I would like to proposed the following specification for Mixins be included as part of Version 1.0 > D Programming Language specification. /All comments are welcomed./ I added this to http://www.prowiki.org/wiki4d/wiki.cgi?FeatureRequestList/Mixins. -- -Anderson: http://badmama.com.au/~anderson/ |
April 30, 2004 Re: COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Posted in reply to fred | Wow, I hadn't realised that this had got so serious! I've been chatting with Walter about a mixins syntax to serve the needs of DTL, but had (carelessly / selfishly / stupidly / ...) not put it up on the group, as I didn't have time for a debate (which I still don't). Roughly, here's my proposal, which, at first glance, appears to be quite a different kettle of fish to what you're talking about: // - Mixins define class/instance methods. // - Mixins do not define *any* instance fields. (Not sure about static fields - what do you think?) // - Mixin methods are added into the mixing class as if the user had typed them in // - Mixins have *no* polymorphic aspects whatsoever. Two classes that each mix // the same mixin are nonetheless completely unrelated // - Mixin methods may "become" polymorphic with respect to any interface(s) that the mixing class is "implement"ing // - If the mixing class already contains a method of the same signature, that "overrides" - prevents incorporation - of that mixin method. Syntax: mixin Ranges(C) // C is the mixing class. { private: typedef C.value_type value_type; // A convenience for the mixin implementation, and also a constraint on C typedef C.index_type index_type; // A convenience for the mixin implementation, and also a constraint on C public: boolean contains(value_type comperand) { foreach(value_type v; cast(C)(this)) // How to get to the real, gestalt, entity. foreach acts as a constraint on C { if(v == comperand) { return cast(boolean)(true); } } return cast(boolean)(false); } . . . } And is used as follows (as in the DTL classes, which require only that the mixing class has value_type and index_type member types, and be freachable): template List(T, B = EmptyBase) { public class List : B // base class , mixes Ranges // Note: do not need to specify mixing class, since it cannot be ambiguous. { } } Note that a mixin could also be a template, but needn't be. In a sense, it's already a template, as it's parameterised by one (and only one) type, its mixing class. Clearly, there are some differences between your proposal and mine: minor: - I don't like the syntax you propose (i.e. the #, @), but this is a pretty minor issue, and will be whatever Walter deems most unambiguous and easy to parse major: - you allow for mixins to provide fields - you allow mixins to introduce a different polymorphic nature to their mixing class - you allow mixins to have constructors, which I do not I disagree with all of these, since it seems that your mixin design is almost a halfway house between SI and MI and, although I understand the motivation, I think we'll be in murky territory. Of course, my perspective may well be covered by my needs. ;) Matthew "fred" <info@fleet-manage.com> wrote in message news:c6s9ck$7go$1@digitaldaemon.com... I would like to proposed the following specification for Mixins be included as part of Version 1.0 D Programming Language specification. All comments are welcomed. MIXINS SPECIFICATION Version 0.1 Introduction What are mixins ? A mixin is a class-like entity whose methods/fields are mixed-in to the mixing class just as if the author of that class had written them manually. As Matthew so neatly put it (see http://www.digitalmars.com/drn-bin/wwwnews?D/28348 ) Why do we need them ? The rational for Mixins is quite compelling... One of the greatest shortcomings of the C++ language from a Object Oriented perspective, is that there is no language support for Aggregated Objects. As such, Aggregation has to be performed programatically, often (incorrectly) using the inheritance mechanism as a coding shortcut. By including language support we provide a direct correlation between OOD using modeling techniques like UML, and OOP. Background Please read the following; http://www.digitalmars.com/drn-bin/wwwnews?D/28455 http://www.digitalmars.com/drn-bin/wwwnews?D/28511 http://www.digitalmars.com/drn-bin/wwwnews?D/28553 Lexical I propose that we use one of the two remaining (common) symbols, i.e. # and @ as well as the keyword mixin. For this document we'll use # as the mixin symbol Syntax There are a number of syntax alternatives that could be incorporated. Alternative A: class <identifier> [: <inherited-class>] [# <aggregated-class> <local-identifier>]* For example; class Lamp : Light # Body cBody # Switch cSwitch # Globe cGlobe # PowerCord cPowerCord { this() { super(); cBody(); // Body construction cGlobe(); // Globe construction cPowerCord(); // PowerCord construction cSwitch(cGlobe,cPowerCord); // Switch construction } }; Alternative B: class <identifier> [: <inherited-class>] [# <aggregated-class> <local-identifier> [, <aggregated-class> <local-identifier>]*] For example; class Lamp : Light # Body cBody , Switch cSwitch , Globe cGlobe , PowerCord cPowerCord { this() { super(); cBody(); // Body construction cGlobe(); // Globe construction cPowerCord(); // PowerCord construction cSwitch(cGlobe,cPowerCord); // Switch construction } }; Semantics The rules for Mixin variables should be the same as class member declarations, except Mixins allow the interfaces of the aggregated class to be included as part of the mixing class. This fact means that it is possible to have multiple versions of the same member name within a mixing class. I propose a simple precedence rule, where the member defined in the class overrides those defined in the aggregated class, and those in the aggregated classes are assigned according to the order they are declared. If this was to take place, a compiler warning message stating "that member X of aggregated class A is taking precedence over that in aggregated class B" should be displayed in the error log. Note: there are probably other things that will need to be considered here ! Conclusion Mixins permit externally declare classes to be used as part of a class, and in so doing provides a real alternative to the Multiple Inheritance option provided for in the C++ language. As such, this relatively insignificant addition to the language should greatly enhance the overall flexibility of the D Programming Language. Comments ! |
April 30, 2004 Re: COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew | Matthew wrote:
> Wow, I hadn't realised that this had got so serious!
>
> I've been chatting with Walter about a mixins syntax to serve the needs of DTL,
> but had (carelessly / selfishly / stupidly / ...) not put it up on the group, as
> I didn't have time for a debate (which I still don't).
>
> Roughly, here's my proposal, which, at first glance, appears to be quite a
> different kettle of fish to what you're talking about:
>
> // - Mixins define class/instance methods.
> // - Mixins do not define *any* instance fields. (Not sure about static fields -
> what do you think?)
> // - Mixin methods are added into the mixing class as if the user had typed them
> in
> // - Mixins have *no* polymorphic aspects whatsoever. Two classes that each mix
> // the same mixin are nonetheless completely unrelated
> // - Mixin methods may "become" polymorphic with respect to any interface(s) that
> the mixing class is "implement"ing
> // - If the mixing class already contains a method of the same signature, that
> "overrides" - prevents incorporation - of that mixin method.
I like it. It is simple and exactly what you need to put mixins to good use. Especially the fact that it doesn't change the classes type will prevent a lot of headaches.
One other thing may be important, though. I think mixins should be combinable to form new mixins (i.e. some kind of multiple inheritance between mixins but without any type issues). I mostly want mixins to be able to conveniently provide default implementations for interfaces. And since interfaces form a hierarchy, the implementations of more specialized interfaces could then re-use implementations of the general interfaces.
The implementation shouldn't be much of a problem since mixins are "typeless", so there can be none of that multiple inheritance chaos we know from C++. It would be the same as simply copying all the code from the different mixins into a new mixin, but allowing the newly created mixin to overwrite methods already defined in one of the base mixins.
Note that this simply means that mixins can mix-in other mixins in the same way that classes can.
Example:
mixin A(X) {...}
mixin B(X) {...}
mixin C(X) mixes A,B {...}
|
April 30, 2004 Re: COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew | Matthew wrote: >Wow, I hadn't realised that this had got so serious! > >I've been chatting with Walter about a mixins syntax to serve the needs of DTL, >but had (carelessly / selfishly / stupidly / ...) not put it up on the group, as >I didn't have time for a debate (which I still don't). > >Roughly, here's my proposal, which, at first glance, appears to be quite a >different kettle of fish to what you're talking about: > >// - Mixins define class/instance methods. >// - Mixins do not define *any* instance fields. (Not sure about static fields - >what do you think?) >// - Mixin methods are added into the mixing class as if the user had typed them >in >// - Mixins have *no* polymorphic aspects whatsoever. Two classes that each mix >// the same mixin are nonetheless completely unrelated >// - Mixin methods may "become" polymorphic with respect to any interface(s) that >the mixing class is "implement"ing >// - If the mixing class already contains a method of the same signature, that >"overrides" - prevents incorporation - of that mixin method. > >Syntax: > >mixin Ranges(C) // C is the mixing class. >{ >private: > typedef C.value_type value_type; // A convenience for the mixin >implementation, and also a constraint on C > typedef C.index_type index_type; // A convenience for the mixin >implementation, and also a constraint on C > >public: > boolean contains(value_type comperand) > { > foreach(value_type v; cast(C)(this)) // How to get to the real, gestalt, >entity. foreach acts as a constraint on C > { > if(v == comperand) > { > return cast(boolean)(true); > } > } > > return cast(boolean)(false); > } > > . . . >} > >And is used as follows (as in the DTL classes, which require only that the mixing >class has value_type and index_type member types, and be freachable): > >template List(T, B = EmptyBase) >{ > public class List > : B // base class > , mixes Ranges // Note: do not need to specify mixing class, since it >cannot be ambiguous. > { > } >} > >Note that a mixin could also be a template, but needn't be. In a sense, it's >already a template, as it's parameterised by one (and only one) type, its mixing >class. > >Clearly, there are some differences between your proposal and mine: > >minor: > >- I don't like the syntax you propose (i.e. the #, @), but this is a pretty minor >issue, and will be whatever Walter deems most unambiguous and easy to parse > >major: > >- you allow for mixins to provide fields >- you allow mixins to introduce a different polymorphic nature to their mixing >class >- you allow mixins to have constructors, which I do not > >I disagree with all of these, since it seems that your mixin design is almost a >halfway house between SI and MI and, although I understand the motivation, I >think we'll be in murky territory. > >Of course, my perspective may well be covered by my needs. ;) > >Matthew > > Just out of interest: It appears to me that mixins (the class part) are very similar to structs? Why couldn't structs be used as mixins instead? I mean something like: struct Ranges(C) // C is the mixing class. { private: typedef C.value_type value_type; // A convenience for the mixin implementation, and also a constraint on C typedef C.index_type index_type; // A convenience for the mixin implementation, and also a constraint on C public: boolean contains(value_type comperand) { foreach(value_type v; cast(C)(this)) // How to get to the real, gestalt, entity. foreach acts as a constraint on C { if(v == comperand) { return cast(boolean)(true); } } return cast(boolean)(false); } . . . } template List(T, B = EmptyBase) { public class List : B // base class , mixes Ranges // Note: do not need to specify mixing class, since it cannot be ambiguous. { } } -- -Anderson: http://badmama.com.au/~anderson/ |
April 30, 2004 Re: COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Posted in reply to Hauke Duden | "Hauke Duden" <H.NS.Duden@gmx.net> wrote in message news:c6t7gs$1m30$1@digitaldaemon.com... > Matthew wrote: > > > Wow, I hadn't realised that this had got so serious! > > > > I've been chatting with Walter about a mixins syntax to serve the needs of DTL, > > but had (carelessly / selfishly / stupidly / ...) not put it up on the group, as > > I didn't have time for a debate (which I still don't). > > > > Roughly, here's my proposal, which, at first glance, appears to be quite a different kettle of fish to what you're talking about: > > > > // - Mixins define class/instance methods. > > // - Mixins do not define *any* instance fields. (Not sure about static fields - > > what do you think?) > > // - Mixin methods are added into the mixing class as if the user had typed them > > in > > // - Mixins have *no* polymorphic aspects whatsoever. Two classes that each mix > > // the same mixin are nonetheless completely unrelated > > // - Mixin methods may "become" polymorphic with respect to any interface(s) that > > the mixing class is "implement"ing > > // - If the mixing class already contains a method of the same signature, that > > "overrides" - prevents incorporation - of that mixin method. > > I like it. It is simple and exactly what you need to put mixins to good use. Especially the fact that it doesn't change the classes type will prevent a lot of headaches. > > One other thing may be important, though. I think mixins should be combinable to form new mixins (i.e. some kind of multiple inheritance between mixins but without any type issues). I mostly want mixins to be able to conveniently provide default implementations for interfaces. And since interfaces form a hierarchy, the implementations of more specialized interfaces could then re-use implementations of the general interfaces. > > The implementation shouldn't be much of a problem since mixins are "typeless", so there can be none of that multiple inheritance chaos we know from C++. It would be the same as simply copying all the code from the different mixins into a new mixin, but allowing the newly created mixin to overwrite methods already defined in one of the base mixins. > > Note that this simply means that mixins can mix-in other mixins in the same way that classes can. > > Example: > > mixin A(X) {...} > mixin B(X) {...} > > mixin C(X) mixes A,B {...} That seems reasonable, except where they had methods with the same signatures. I don't like the DAG crap that would transpire as a result. |
April 30, 2004 Re: COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Posted in reply to J Anderson | "J Anderson" <REMOVEanderson@badmama.com.au> wrote in message news:c6t9ri$1pfq$1@digitaldaemon.com... > Matthew wrote: > > >Wow, I hadn't realised that this had got so serious! > > > >I've been chatting with Walter about a mixins syntax to serve the needs of DTL, > >but had (carelessly / selfishly / stupidly / ...) not put it up on the group, as > >I didn't have time for a debate (which I still don't). > > > >Roughly, here's my proposal, which, at first glance, appears to be quite a different kettle of fish to what you're talking about: > > > >// - Mixins define class/instance methods. > >// - Mixins do not define *any* instance fields. (Not sure about static fields - > >what do you think?) > >// - Mixin methods are added into the mixing class as if the user had typed them > >in > >// - Mixins have *no* polymorphic aspects whatsoever. Two classes that each mix > >// the same mixin are nonetheless completely unrelated > >// - Mixin methods may "become" polymorphic with respect to any interface(s) that > >the mixing class is "implement"ing > >// - If the mixing class already contains a method of the same signature, that > >"overrides" - prevents incorporation - of that mixin method. > > > >Syntax: > > > >mixin Ranges(C) // C is the mixing class. > >{ > >private: > > typedef C.value_type value_type; // A convenience for the mixin > >implementation, and also a constraint on C > > typedef C.index_type index_type; // A convenience for the mixin > >implementation, and also a constraint on C > > > >public: > > boolean contains(value_type comperand) > > { > > foreach(value_type v; cast(C)(this)) // How to get to the real, gestalt, > >entity. foreach acts as a constraint on C > > { > > if(v == comperand) > > { > > return cast(boolean)(true); > > } > > } > > > > return cast(boolean)(false); > > } > > > > . . . > >} > > > >And is used as follows (as in the DTL classes, which require only that the mixing > >class has value_type and index_type member types, and be freachable): > > > >template List(T, B = EmptyBase) > >{ > > public class List > > : B // base class > > , mixes Ranges // Note: do not need to specify mixing class, since it > >cannot be ambiguous. > > { > > } > >} > > > >Note that a mixin could also be a template, but needn't be. In a sense, it's already a template, as it's parameterised by one (and only one) type, its mixing > >class. > > > >Clearly, there are some differences between your proposal and mine: > > > >minor: > > > >- I don't like the syntax you propose (i.e. the #, @), but this is a pretty minor > >issue, and will be whatever Walter deems most unambiguous and easy to parse > > > >major: > > > >- you allow for mixins to provide fields > >- you allow mixins to introduce a different polymorphic nature to their mixing > >class > >- you allow mixins to have constructors, which I do not > > > >I disagree with all of these, since it seems that your mixin design is almost a > >halfway house between SI and MI and, although I understand the motivation, I think we'll be in murky territory. > > > >Of course, my perspective may well be covered by my needs. ;) > > > >Matthew > > > > > > Just out of interest: It appears to me that mixins (the class part) are very similar to structs? Why couldn't structs be used as mixins instead? Because a struct does not have a mixing class. If you made the struct a template, that would mean that mixins could not be templates - which they can in my proposal - because the "template" syntax would already be used in making it a mixin. There are several other reasons why it can't be so, but that's good enough. > > I mean something like: > > struct Ranges(C) // C is the mixing class. > { > private: > typedef C.value_type value_type; // A convenience for the mixin > implementation, and also a constraint on C > typedef C.index_type index_type; // A convenience for the mixin > implementation, and also a constraint on C > > public: > boolean contains(value_type comperand) > { > foreach(value_type v; cast(C)(this)) // How to get to the real, gestalt, > entity. foreach acts as a constraint on C > { > if(v == comperand) > { > return cast(boolean)(true); > } > } > > return cast(boolean)(false); > } > > . . . > } > > > template List(T, B = EmptyBase) > { > public class List > : B // base class > , mixes Ranges // Note: do not need to specify mixing class, since it > cannot be ambiguous. > { > } > } > > > -- > -Anderson: http://badmama.com.au/~anderson/ |
April 30, 2004 Re: COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew | Matthew wrote: >>Just out of interest: It appears to me that mixins (the class part) are >>very similar to structs? Why couldn't structs be used as mixins instead? >> >> > >Because a struct does not have a mixing class. If you made the struct a template, >that would mean that mixins could not be templates - which they can in my >proposal - because the "template" syntax would already be used in making it a >mixin. > >There are several other reasons why it can't be so, but that's good enough. > > I thought there was a reason, thanks. -- -Anderson: http://badmama.com.au/~anderson/ |
April 30, 2004 Re: COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew | In article <c6sb58$a39$1@digitaldaemon.com>, Matthew says... > >Wow, I hadn't realised that this had got so serious! > >I've been chatting with Walter about a mixins syntax to serve the needs of DTL, but had (carelessly / selfishly / stupidly / ...) not put it up on the group, as I didn't have time for a debate (which I still don't). Real work has been keeping me busy for 14 days straight here but I will make a few comments. > >Roughly, here's my proposal, which, at first glance, appears to be quite a different kettle of fish to what you're talking about: > >// - Mixins define class/instance methods. >// - Mixins do not define *any* instance fields. (Not sure about static fields - >what do you think?) This seems a little arbitrary. Why should this restriction be made especially give the implementation just below. I can think of a number of reason to want fields. >// - Mixin methods are added into the mixing class as if the user had typed them in Yes >// - Mixins have *no* polymorphic aspects whatsoever. Two classes that each mix // the same mixin are nonetheless completely unrelated Yes >// - Mixin methods may "become" polymorphic with respect to any interface(s) that >the mixing class is "implement"ing >// - If the mixing class already contains a method of the same signature, that >"overrides" - prevents incorporation - of that mixin method. Does this include methods from a base of the class? I would say that any directly defined members of the class take precedence over the mixin method but the mixin method take precedence over and base class method. My view point on mixins is in line with Fred's post. ( See my reply to him. ) The major difference is that I think the mixin declaration needs to go into the class body not the header. The reason for this is that I think mixins should be able to be able to be parameterized by items from the declaration scope. |
April 30, 2004 Re: COMMENTS: Mixins Specification | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew | Matthew wrote:
>>Note that this simply means that mixins can mix-in other mixins in the
>>same way that classes can.
>>
>>Example:
>>
>>mixin A(X) {...}
>>mixin B(X) {...}
>>
>>mixin C(X) mixes A,B {...}
>
>
> That seems reasonable, except where they had methods with the same signatures. I
> don't like the DAG crap that would transpire as a result.
I think the same rules that are used when a class uses multiple mixins should apply. How is it handled there?
The optimal thing would be if such conflicts are silently ignored if the function's code is the same in all mixins. Might be a little complicated to implement though (or it may be a simple memcmp - probably only Walter knows).
Otherwise I see two solutions:
1) it is an error and the class must override such functions
2) use a simple precedence rule, like first mixin wins (according to the order in which they are mentioned in the class definition). I like this one because of its simplicity. One could argue that it can hide mistakes, but it is basically the same thing as the rule that class methods win over mixin methods. I.e. "read the class definition from left to right and use the first matching method you find in the mentioned entities".
Hauke
|
Copyright © 1999-2021 by the D Language Foundation