Thread overview | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 14, 2003 D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Walter asked me to post this on the newsgroup, my original mail below. Note to below: Thinking some more about the sugg. about filtering mixins through an interface, I think it will not work because mixins may also need to include helper functions on non-public members i.e. mixins has implementation detail an interface does not know about. But that does not change the general idea of using mixins. Mikkel <snip original mail> [Walter]: I think mixins are a good idea. Why not post this to the D newsgroup? There are some pretty smart people there to comment on it. ----- Original Message ----- From: "Mikkel Fahnøe Jørgensen" To: <Walter> Sent: Sunday, December 14, 2003 7:35 AM Subject: D interfaces, mixins? D has interfaces where C++ has multiple inheritance. This is generally a good thing. In C++ you frequently have a situation where you manually have to re-write functions of base classes (or delegates) and writing stub calls to base classes. This is very tedious and error prone. The use of interfaces in D helps resolve a lot of issues with multiple inheritance. As far as I can see much like in Java. It seems to me like in you do not avoid the need to write these forwarding calls in D, just as in Java. The Ruby programming language has the same concept of single inheritence, but introduces mixins (I think it originates from small-talk or similar. A mixin kind of copy pastes the members of one class into another class withing the semantic meaning being as if you had written the code manually. Here is a possible syntax for mixins: interface IStream { char [] read(); void write(char []); } class StdReader { char [] read() { ... read and return data; } class StdWriter { void write(char [] data) { class MyDataStorage : IStream, mixin StdReader, mixin StdWriter { } Mixins don't have the same ambiguities as multiple inheritance. If multiple mixins are included which have overlapping members, it is either an error, or the definition of the last mixin. If a mixin member conflicts with a member of the class it is being mixed into, it is an error, or the member overrides the conflicting mixin definition. class StdStream { char [] Read() { ... }; void StdWrite(char [] data) { ... } } class MyStorage : IStream, StdStream { void Write(char []) { ... } } Mixins would require some more thinking, but I believe this could be a killer feature of D. The great thing about mixins and interface vs. multiple inheritance is that you separate interface from implementation. But interfaces alone does not easily allow for easy implementations. A more advanced mixin feature could be to filter a mixin through an interface such that only those members of a mixins that implements one or more interface members would be included: interface IReader { char [] Read(); } class MyStorage2 : IStream, mixin StdStream for IReader { Write(char[]) { ... } } It could also be that mixins shouldn't be standard classes but special mixin types. In Ruby you have classes and modules. You mixin modules, not classes. The syntax could be: mixin MReader { char [] Read() { ... } } interface IReader { char [] Read(); } class MyReader : IReader, MReader {} I know that mixins may seem a lot like multiple inheritance. But you cannot cast to a mixin type. A mixin is just a macro for making it easier to write a class implementation. More info on Ruby www.ruby-lang.org Regards Mikkel Fahnøe Jørgensen |
December 14, 2003 Re: D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Posted in reply to MikkelFJ | "MikkelFJ" <mikkel@dvideNOSPAMDOT.com> wrote in news:briles$9ku$1@digitaldaemon.com: > The Ruby programming language has the same concept of single inheritence, but introduces mixins (I think it originates from small-talk or similar. > > A mixin kind of copy pastes the members of one class into another class withing the semantic meaning being as if you had written the code manually. I am a big advocate of mixins. Mixins can already be done in D with templates but the syntax is very clumsy. It basically involves inheriting from a chain of template instantiations. The following code segment is an example of this and actaully compiles. template IOTemplate(BASE) { class StdReader : BASE { char[] read() { /*... read and return data;*/ return ""; } } class StdWriter : BASE { void write(char[] data) { /*... write data;*/ } } } class Nothing { } class MyDataStorage : instance IOTemplate( instance IOTemplate(Nothing).StdReader ).StdWriter { } int main(char[][] argv) { MyDataStorage my = new MyDataStorage(); return 0; } Of course you are right that you may want to use mixins with interfaces and does present another inconvenience with the syntax. If change MyDataStorage to use the IOStream interface you will receive a compiler error. interface IOStream { char [] read(); void write(char []); } class MyDataStorage : instance IOTemplate( instance IOTemplate(Nothing).StdReader ).StdWriter, IOStream { } The compler error is: mixin.d: class MyDataStorage interface function IOStream.read is not implemented The reason for this error is that in D a class can't use functions inherited from a base class to fill the slots from the interface definition. All the interface functions must be directly defined in the class that declares the interface. So to fix the compiler error you would have to do this: class MyDataStorage : instance IOTemplate( instance IOTemplate(Nothing).StdReader ).StdWriter, IOStream { char[] read() { return super.read(); } void write(char[] param) { super.write(param); } } I think this solution is terribly inconvenent. There is going to be (hopefully, please, please) another pass at the template implementation in D that will address the general template issues. So this way of doing mixins will hopefully be easier. |
December 14, 2003 Re: D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Posted in reply to MikkelFJ | The term "mixin" comes from the bits of biscuits (cookies to the Western Hemipherians), cakes (buns to the Aussies), scones (or sc"oa"nes for those on the west side of the Pennines) and cheesecakes, that were added into ice-cream (glace to the French, gelato to the Italians) to make it extra-specially yummy. I think it's a western USA term, but I couldn't be sure. In terms of programming, the mixin notion you propose is a nice idea, and one that is certain to be found either automatically (as you propose) or manually (a la Java) as D grows. My concern is whether you've (or Ruby's) addressed the issue of name-clash when multiple mixin-provided interface method names clash. But, AFAIAA, this is an issue not yet resolved in D irrespective of mixins. Just disallowing inheritance from two clashing interfaces doesn't seem like much of an answer to me. This is one way in which multiple inheritance is a must. Otherwise, I like it. Let's have an experimental go with it in 0.78. :) Matthew "MikkelFJ" <mikkel@dvideNOSPAMDOT.com> wrote in message news:briles$9ku$1@digitaldaemon.com... > Walter asked me to post this on the newsgroup, my original mail below. > > Note to below: Thinking some more about the sugg. about filtering mixins through an interface, I think it will not work because mixins may also need > to include helper functions on non-public members i.e. mixins has implementation detail an interface does not know about. But that does not change the general idea of using mixins. > > Mikkel > > <snip original mail> > > [Walter]: I think mixins are a good idea. Why not post this to the D > newsgroup? There > are some pretty smart people there to comment on it. > > ----- Original Message ----- > From: "Mikkel Fahnøe Jørgensen" > To: <Walter> > Sent: Sunday, December 14, 2003 7:35 AM > Subject: D interfaces, mixins? > > > D has interfaces where C++ has multiple inheritance. This is generally a good thing. > > In C++ you frequently have a situation where you manually have to re-write functions of base classes (or delegates) and writing stub calls to base classes. This is very tedious and error prone. > > The use of interfaces in D helps resolve a lot of issues with multiple inheritance. As far as I can see much like in Java. > > It seems to me like in you do not avoid the need to write these forwarding calls in D, just as in Java. > > The Ruby programming language has the same concept of single inheritence, but introduces mixins (I think it originates from small-talk or similar. > > A mixin kind of copy pastes the members of one class into another class withing the semantic meaning being as if you had written the code manually. > > Here is a possible syntax for mixins: > > interface IStream { char [] read(); void write(char []); } > class StdReader { char [] read() { ... read and return data; } > class StdWriter { void write(char [] data) { > class MyDataStorage : IStream, mixin StdReader, mixin StdWriter { } > > Mixins don't have the same ambiguities as multiple inheritance. > If multiple mixins are included which have overlapping members, it is either > an error, or the definition of the last mixin. If a mixin member conflicts with a member of the class it is being mixed into, it is an error, or the member overrides the conflicting mixin definition. > > class StdStream { char [] Read() { ... }; void StdWrite(char [] data) { > ... } } > class MyStorage : IStream, StdStream { void Write(char []) { ... } } > > Mixins would require some more thinking, but I believe this could be a killer feature of D. > > The great thing about mixins and interface vs. multiple inheritance is that > you separate interface from implementation. But interfaces alone does not easily allow for easy implementations. > > A more advanced mixin feature could be to filter a mixin through an interface such that only those members of a mixins that implements one or more interface members would be included: > > interface IReader { char [] Read(); } > class MyStorage2 : IStream, mixin StdStream for IReader { Write(char[]) { > ... } } > > It could also be that mixins shouldn't be standard classes but special mixin > types. In Ruby you have classes and modules. You mixin modules, not classes. > The syntax could be: > > mixin MReader { char [] Read() { ... } } > interface IReader { char [] Read(); } > class MyReader : IReader, MReader {} > > I know that mixins may seem a lot like multiple inheritance. But you cannot > cast to a mixin type. A mixin is just a macro for making it easier to write > a class implementation. > > > More info on Ruby > www.ruby-lang.org > > Regards > > Mikkel Fahnøe Jørgensen > > > > |
December 15, 2003 Re: D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew Wilson | How about requiring any name clashed mixins to be explicity referenced by their base class.
ie
class A { void doSomething();
void somethingA(); }
class B { void doSomething();
void somethingB(); }
class C : mixin A, mixin B
{
};
And be required to call functions as
C.somethingA();
C.somethingB();
C.A.doSomething();
C.B.doSomething();
Brad
Matthew Wilson wrote:
> The term "mixin" comes from the bits of biscuits (cookies to the Western
> Hemipherians), cakes (buns to the Aussies), scones (or sc"oa"nes for those
> on the west side of the Pennines) and cheesecakes, that were added into
> ice-cream (glace to the French, gelato to the Italians) to make it
> extra-specially yummy. I think it's a western USA term, but I couldn't be
> sure.
>
> In terms of programming, the mixin notion you propose is a nice idea, and
> one that is certain to be found either automatically (as you propose) or
> manually (a la Java) as D grows.
>
> My concern is whether you've (or Ruby's) addressed the issue of name-clash
> when multiple mixin-provided interface method names clash. But, AFAIAA, this
> is an issue not yet resolved in D irrespective of mixins. Just disallowing
> inheritance from two clashing interfaces doesn't seem like much of an answer
> to me. This is one way in which multiple inheritance is a must.
>
> Otherwise, I like it. Let's have an experimental go with it in 0.78. :)
>
> Matthew
>
> "MikkelFJ" <mikkel@dvideNOSPAMDOT.com> wrote in message
> news:briles$9ku$1@digitaldaemon.com...
>
>>Walter asked me to post this on the newsgroup, my original mail below.
>>
>>Note to below: Thinking some more about the sugg. about filtering mixins
>>through an interface, I think it will not work because mixins may also
>
> need
>
>>to include helper functions on non-public members i.e. mixins has
>>implementation detail an interface does not know about. But that does not
>>change the general idea of using mixins.
>>
>>Mikkel
>>
>><snip original mail>
>>
>>[Walter]: I think mixins are a good idea. Why not post this to the D
>>newsgroup? There
>>are some pretty smart people there to comment on it.
>>
>>----- Original Message -----
>>From: "Mikkel Fahnøe Jørgensen"
>>To: <Walter>
>>Sent: Sunday, December 14, 2003 7:35 AM
>>Subject: D interfaces, mixins?
>>
>>
>>D has interfaces where C++ has multiple inheritance. This is generally a
>>good thing.
>>
>>In C++ you frequently have a situation where you manually have to re-write
>>functions of base classes (or delegates) and writing stub calls to base
>>classes. This is very tedious and error prone.
>>
>>The use of interfaces in D helps resolve a lot of issues with multiple
>>inheritance. As far as I can see much like in Java.
>>
>>It seems to me like in you do not avoid the need to write these forwarding
>>calls in D, just as in Java.
>>
>>The Ruby programming language has the same concept of single inheritence,
>>but introduces mixins (I think it originates from small-talk or similar.
>>
>>A mixin kind of copy pastes the members of one class into another class
>>withing the semantic meaning being as if you had written the code
>
> manually.
>
>>Here is a possible syntax for mixins:
>>
>>interface IStream { char [] read(); void write(char []); }
>>class StdReader { char [] read() { ... read and return data; }
>>class StdWriter { void write(char [] data) {
>>class MyDataStorage : IStream, mixin StdReader, mixin StdWriter { }
>>
>>Mixins don't have the same ambiguities as multiple inheritance.
>>If multiple mixins are included which have overlapping members, it is
>
> either
>
>>an error, or the definition of the last mixin. If a mixin member conflicts
>>with a member of the class it is being mixed into, it is an error, or the
>>member overrides the conflicting mixin definition.
>>
>>class StdStream { char [] Read() { ... }; void StdWrite(char [] data) {
>>... } }
>>class MyStorage : IStream, StdStream { void Write(char []) { ... } }
>>
>>Mixins would require some more thinking, but I believe this could be a
>>killer feature of D.
>>
>>The great thing about mixins and interface vs. multiple inheritance is
>
> that
>
>>you separate interface from implementation. But interfaces alone does not
>>easily allow for easy implementations.
>>
>>A more advanced mixin feature could be to filter a mixin through an
>>interface such that only those members of a mixins that implements one or
>>more interface members would be included:
>>
>>interface IReader { char [] Read(); }
>>class MyStorage2 : IStream, mixin StdStream for IReader { Write(char[]) {
>>... } }
>>
>>It could also be that mixins shouldn't be standard classes but special
>
> mixin
>
>>types. In Ruby you have classes and modules. You mixin modules, not
>
> classes.
>
>>The syntax could be:
>>
>>mixin MReader { char [] Read() { ... } }
>>interface IReader { char [] Read(); }
>>class MyReader : IReader, MReader {}
>>
>>I know that mixins may seem a lot like multiple inheritance. But you
>
> cannot
>
>>cast to a mixin type. A mixin is just a macro for making it easier to
>
> write
>
>>a class implementation.
>>
>>
>>More info on Ruby
>>www.ruby-lang.org
>>
>>Regards
>>
>>Mikkel Fahnøe Jørgensen
>>
>>
>>
>>
>
>
>
|
December 15, 2003 Re: D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Posted in reply to MikkelFJ | (I'm glad! :-) I suggest "interface delegation" like Delphi. It fits to "COM"(Component-Object-Model) well, and necessary to "aggregation" of COM. //sample (Delphi) type MyClass = class(ParentClass, InterfaceA) private ARef: TheClassImplementsInterfaceA; public property A: TheClassImplementsInterfaceA read ARef implements InterfaceA; end; //D? class MyClass : ParentClass, InterfaceA { private TheClassImplementsInterfaceA aRef; TheClassImplementsInterfaceA a() implements InterfaceA { return aRef; } //property } MyClass can override some methods of InterfaceA, and remaining methods dispatched to "aRef". We can exchange aRef at run-time. It's a little advantage. Another advantage is that "interface delegation" don't require special definition like "mixin MReader { char [] Read() { ... } }". "Interface delegation" is able to use the existing class. (if you can read Japanease, please read a shinichiro.h's analysis. "Method delegation" like "Uva" interests me, too. http://d.hatena.ne.jp/shinichiro_h/20031213#p1) Thanks. YT |
December 15, 2003 Re: D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Posted in reply to Y.Tomino | I like this idea. "Y.Tomino" <demoonlit@inter7.jp> wrote in news:brj1ui$r60$1@digitaldaemon.com: > (I'm glad! :-) > > I suggest "interface delegation" like Delphi. > It fits to "COM"(Component-Object-Model) well, > and necessary to "aggregation" of COM. > > //sample (Delphi) > type > MyClass = class(ParentClass, InterfaceA) > private > ARef: TheClassImplementsInterfaceA; > public > property A: TheClassImplementsInterfaceA read ARef implements > InterfaceA; > end; > > //D? > class MyClass : ParentClass, InterfaceA > { > private TheClassImplementsInterfaceA aRef; > TheClassImplementsInterfaceA a() implements InterfaceA { return > aRef; } > //property > } > > MyClass can override some methods of InterfaceA, > and remaining methods dispatched to "aRef". > We can exchange aRef at run-time. It's a little advantage. > > Another advantage is that "interface delegation" don't require special > definition > like "mixin MReader { char [] Read() { ... } }". > "Interface delegation" is able to use the existing class. > > (if you can read Japanease, please read a shinichiro.h's analysis. > "Method delegation" like "Uva" interests me, too. > http://d.hatena.ne.jp/shinichiro_h/20031213#p1) > > Thanks. > YT > > |
December 15, 2003 Re: D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew Wilson | Which reminds me, I don't think the name-clash problem with multiple interfaces with the same methods that are meant to have different uses was every addressed. IMHO, I haven't programmed in C#, but I still like the way it handle's this problem. In article <brit5d$kh5$1@digitaldaemon.com>, Matthew Wilson says... > >The term "mixin" comes from the bits of biscuits (cookies to the Western >Hemipherians), cakes (buns to the Aussies), scones (or sc"oa"nes for those >on the west side of the Pennines) and cheesecakes, that were added into >ice-cream (glace to the French, gelato to the Italians) to make it >extra-specially yummy. I think it's a western USA term, but I couldn't be >sure. > >In terms of programming, the mixin notion you propose is a nice idea, and >one that is certain to be found either automatically (as you propose) or >manually (a la Java) as D grows. > >My concern is whether you've (or Ruby's) addressed the issue of name-clash when multiple mixin-provided interface method names clash. But, AFAIAA, this is an issue not yet resolved in D irrespective of mixins. Just disallowing inheritance from two clashing interfaces doesn't seem like much of an answer to me. This is one way in which multiple inheritance is a must. > >Otherwise, I like it. Let's have an experimental go with it in 0.78. :) > >Matthew > |
December 15, 2003 Re: D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Posted in reply to brad beveridge | brad beveridge wrote:
> How about requiring any name clashed mixins to be explicity referenced by their base class.
>
> ie
> class A { void doSomething();
> void somethingA(); }
> class B { void doSomething();
> void somethingB(); }
> class C : mixin A, mixin B
> {
> };
>
> And be required to call functions as
> C.somethingA();
> C.somethingB();
> C.A.doSomething();
> C.B.doSomething();
>
> Brad
>
I don't like this style because you have direct calls and something like indirekt calls to methods of mixins. You should have define the behavior if it is not clear. You could make those clashed methods something like abstract methods. Then the compiler would say that there is something wrong...
I'm using your example.
class C: mixin A, mixin B
{
void something(){A.somethingA();}
}
You could use the base mixin versions by downcasting....
Stephan
|
December 15, 2003 Re: D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Posted in reply to brad beveridge |
> How about requiring any name clashed mixins to be explicity referenced by their base class.
>
> ie
> class A { void doSomething();
> void somethingA(); }
> class B { void doSomething();
> void somethingB(); }
> class C : mixin A, mixin B
> {
> };
>
> And be required to call functions as
> C.somethingA();
> C.somethingB();
> C.A.doSomething();
> C.B.doSomething();
I don't think this is a particularly good idea because it works against the entire idea that mixins simply implements the class. The above adds some level of scoping to the mixins and you are getting closer to the problems of multiple inheritance.
However, the related problem of clashing interface members could perhaps be
resolved this way:
(disclaimer - I'm not that deep into the semantics of D to know if this is
already covered somehow)
interface IA { void foo(); }
interface IB { void foo(); }
class X : IA, IB { IA.foo() { ... }; IB foo() { ... } }
This could be extended to mixins:
class A { IA.foo() { ... } } // can't be instantiated due to lack of
interface, but can be mixed in
class B { IB.foo() {...} } // ditto
class X : IA, IB, A, B {}
This leverages the idea that interfaces define the interface and mixins are just helpers.
Sometimes we want one method to implement clashing names in interfaces: For example an array interface and a list interface. A class could expose both interfaces and both interfaces have a "int size();" method:
interface IVector { int size(); ... }
interface IList { int size(); ... }
class Collection : IVector, IList { int _size; int size() { return size(); }
... }
Here size maps to both interfaces.
The problem is that all this semantic rules makes it difficult to understand and remember and thus again approaching the complexity of C++ multiple inheritance.
Mikkel
|
December 15, 2003 Re: D interfaces and mixins | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew Wilson | "Matthew Wilson" <matthew.hat@stlsoft.dot.org> skrev i en meddelelse news:brit5d$kh5$1@digitaldaemon.com... > My concern is whether you've (or Ruby's) addressed the issue of name-clash when multiple mixin-provided interface method names clash. But, AFAIAA, this I'm sure there are a number of stones to be turned before mixins can be considered to be a practical concept. I intentionally left the issue of clashing mixins open by suggesting either an error or that the last mixin definition wins. (I did not originally address interface member clashes). Clashes in Ruby mixins are resolved by letting the last definition win. This is due to the dynamic nature of Ruby because you can always redefine a method in Ruby (save frozen classes). This may or may not be a suitable behavior of a somewhat strongely typed language like D. It's mostly a matter of philosophy. I would find redefinition useful, but I also think D is close enough to C++ for users to expect an error in case of clashes. Also refer to my other posting about the option to prefix methods with interface names answering Brad Beveridge. > is an issue not yet resolved in D irrespective of mixins. Just disallowing inheritance from two clashing interfaces doesn't seem like much of an answer > to me. This is one way in which multiple inheritance is a must. This was also a source of inspiration for my other posting concerned with interface prefixes. Mikkel |
Copyright © 1999-2021 by the D Language Foundation