D - D interfaces and mixins
- MikkelFJ (66/66) Dec 14 2003 Walter asked me to post this on the newsgroup, my original mail below.
- Patrick Down (79/86) Dec 14 2003 I am a big advocate of mixins. Mixins can already
-
Walter
(3/5)
Dec 17 2003
Yes.
- Matthew Wilson (26/92) Dec 14 2003 The term "mixin" comes from the bits of biscuits (cookies to the Western
- brad beveridge (17/164) Dec 14 2003 How about requiring any name clashed mixins to be explicity referenced
- Stephan Wienczny (13/33) Dec 15 2003 I don't like this style because you have direct calls and something like...
- MikkelFJ (30/45) Dec 15 2003 I don't think this is a particularly good idea because it works against ...
- Luke D (5/21) Dec 15 2003 Which reminds me, I don't think the name-clash problem with multiple int...
- MikkelFJ (20/25) Dec 15 2003 this
- Y.Tomino (32/32) Dec 14 2003 (I'm glad! :-)
- Patrick Down (3/45) Dec 14 2003 I like this idea.
- MikkelFJ (51/58) Dec 15 2003 ...
- Benji Smith (7/7) Dec 15 2003 The only possible problem that crosses my mind is that mixins will need ...
- Matthew Wilson (7/14) Dec 15 2003 You should write a book!
- Benji Smith (3/5) Dec 16 2003 Ouch.
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
Dec 14 2003
"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.
Dec 14 2003
"Patrick Down" <pat codemoon.com> wrote in message news:Xns9451B74F0618Epatcodemooncom 63.105.9.61...There is going to be (hopefully, please, please) another pass at the template implementation in DYes. <g>
Dec 17 2003
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 alsoneedto 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 codemanually.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 iseitheran 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 isthatyou 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 specialmixintypes. In Ruby you have classes and modules. You mixin modules, notclasses.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 youcannotcast to a mixin type. A mixin is just a macro for making it easier towritea class implementation. More info on Ruby www.ruby-lang.org Regards Mikkel Fahnøe Jørgensen
Dec 14 2003
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 alsoneedto 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 codemanually.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 iseitheran 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 isthatyou 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 specialmixintypes. In Ruby you have classes and modules. You mixin modules, notclasses.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 youcannotcast to a mixin type. A mixin is just a macro for making it easier towritea class implementation. More info on Ruby www.ruby-lang.org Regards Mikkel Fahnøe Jørgensen
Dec 14 2003
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(); BradI 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
Dec 15 2003
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
Dec 15 2003
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. 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
Dec 15 2003
"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 ananswerto 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
Dec 15 2003
(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
Dec 14 2003
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
Dec 14 2003
"Y.Tomino" <demoonlit inter7.jp> skrev i en meddelelse news:brj1ui$r60$1 digitaldaemon.com...(I'm glad! :-) I suggest "interface delegation" like Delphi....property A: TheClassImplementsInterfaceA read ARef implementsThis is a nice concept. I do not think it entirely replaces the concept of mixins but it certainly does solve a number of issues. There are also performance issues - mixins are not only useful for late binding interface implementation. Also mixins decouples "who implements what" from the interface. In any case this is a nice idea. If the delegate concept is implemented, one might argue that mixins will not add enough benefits to warrant the added complexity of the language ... but then again it could be useful in its own right :-) BTW, Ruby also has a concept of delegates - but this is implemented on top of the language thanks to reflection and the highly dynamic nature of this language. As far as I am aware delegates are not used nearly as often as mixins in Ruby, but then again Ruby doesn't really have the same concept (or need for) of interfaces. One example of mixins in Ruby: An array module is mixed into a number of classes offering collections. Another mixin could then be created to piggy-backs on array methods by supplying a sort method working on the standard array methods. Note that there isn't really an array interface, just a convention of what methods an array has. (This is known as Duck typing: If it quacks like a duck, it is a duck.). This is a way to use mixins without using interfaces. Contrary to Ruby, D is statically typed. This means the compiler would discover errors Ruby would only discover in runtime. Yet mixins adds a rather informal dynamic nature to class design while avoiding some of the potential runtime errors seen in Ruby. There are links from here to the concepts of algorithms in C++ STL. You can have algorithms mixed in. Mixins could probably be templated as well. class DiskRecordSet { T get(int index) { ... }; void set(T value) { ... }; int size() { ...} } class MemArray { T get(int index) { ... }; void set(T value) { ... }; int size() { ...} } class QuickSorter { void sort() { ... impl. quick sort using get, set, size methods } } class MergeSorter { void sort() { ... impl. merge sort using get, set, size methods } } class Filer : mixin DiskRecordSet, mixin MergeSorter {} class WorkingSet : mixin MemArray, mixin MergeSorter {} These operations do not work in interfaces but rather on conventions. This makes it easy to create efficient implementations with relying heavily on specific class types which would require templates that is often more tedious to work with. At the same time mixins are so much convention that it is useful to combine them with interfaces at the inter-module level. Thus we could combine the above storage implementations with stream interfaces as shown earlier.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.Hmm not necessarily. The mixin definition was just a suggestion. My proposal also considers the alternative of allowing ordinary classes to be mixed in: class Reader { char [] Read() {...} } class Storage : mixin Reader { .... } Mikkel
Dec 15 2003
The only possible problem that crosses my mind is that mixins will need some mechanism to access the data members of the classes that import them. There will also need to be a safety mechanism to keep mixins from modifying class data that they shouldn't be touching. It's late at night, though, and I can't think of any example syntax that illustrates what I'm talking about. --Benji
Dec 15 2003
You should write a book! 12-months of brain freeze. ;( "Benji Smith" <dlanguage xxagg.com> wrote in message news:brm8ue$2mb0$1 digitaldaemon.com...The only possible problem that crosses my mind is that mixins will needsomemechanism to access the data members of the classes that import them.There willalso need to be a safety mechanism to keep mixins from modifying classdata thatthey shouldn't be touching. It's late at night, though, and I can't think of any example syntax that illustrates what I'm talking about. --Benji
Dec 15 2003
On Tue, 16 Dec 2003 17:47:03 +1100, "Matthew Wilson" <matthew.hat stlsoft.dot.org> wrote:You should write a book! 12-months of brain freeze. ;(Ouch.
Dec 16 2003