Re: Multiple subtyping with alias this and nested classes
Yigal Chripun wrote: On 06/10/2009 02:15, Andrei Alexandrescu wrote: Yigal Chripun wrote: I think 'alias this' is a powerful feature. Given the constraints like easy for the compiler writer to implement and we have many other things to do, I doubt traits or something like that will be or needs to be in the language. Alias this is powerful black magic. being powerful doesn't make it any less dark. So how does this work? Alias this was meant very clearly for allowing subtyping. Conversely, using it for subtyping is precisely how it was meant to be used. How exactly did you decide it was a hack or black magic or whatever? Andrei D already has syntax for sub-typing reference types and alias this introduces a completely different syntax doing the same for value types which is bad human interface IMO. Inheritance is a bit more than just subtyping, for example it entails the prefix property (otherwise it wouldn't be very practical). That's why D only allows single inheritance of state; multiple inheritance of state causes more problems than it solves. That's also why alias this is a very flexible complement to inheritance - it offers subtyping without requiring the prefix property and leaves layout to the discretion of the user. it also mixes two concepts - sub-typing and opImplicitCast (as i recall, this is done by alias this to a function) opImplicitCast hasn't been implemented and probably alias this will render it unnecessary. I don't see a dangerous conflation. we discussed this in the past already and IIRC you agreed with me about implementing compile time inheritance for structs which I feel is much cleaner and more consistent with the existing syntax of interfaces. Maybe there's a misunderstanding. Inheritance of interfaces for structs (which is different from what alias this helps with) was something that Walter and I considered interesting to pursue for simplifying concept checking. However, recent developments clarified that that's not enough (I even deleted the related enhancement requests from bugzilla). Currently I'm considering a reflection-based concept checking, but it's too crude an idea to discuss it at the moment. Andrei
Re: Multiple subtyping with alias this and nested classes
On Tue, 06 Oct 2009 00:52:42 +0200, Yigal Chripun yigal...@gmail.com wrote: I see you want to discuss the details of the renaming mechanism, while I just talked about the general idea itself until now. Yes, I understand the idea and am trying to imagine it in the context of D. we have two cases: regular and mixins. for case a it's simple, the class itself lists the renames: Interface A { void foo(); } Interface B { void foo(); } class C : A, B { alias A.foo func1; // or similar syntax to mark the renaming alias B.foo func2; // ditto override void func1() {...} // C.func1 overrides A.foo override void func2() {...} // C.func2 overrides B.foo } Ok, that looks good. case 2, mixins: I think some sort of annotations by the programmer is needed. class C : A, B { alias A.foo func1; // or similar syntax to mark the renaming alias B.foo func2; // ditto // hypothetical syntax to connect mixins to interfaces // the compiler will apply the rename rules of this class assuming that // any references to foo in ImplA are A.foo and will be renamed to // func1 in C // if the mixin explicitly specifies the interface (e.g B.foo) than the // compiler already knows what to map this to. mixin ImplA A; mixin ImplB B; } This exact syntax won't work but I see your point. btw, this all can be done in a much simpler way with (hygienic) AST Macros. Sadly (or for the better), we are not going to have macros in the near future. I don't think I want non virtual MI in D since it is more trouble than it's worth. but *if* we discuss this, I think my suggested semantics are simpler. The syntax probably can be much better but that's a secondary issue IMO. It's unrelated to virtual MI. See Sergey Gromov's post. We are discussing this only because it's a real world problem that has no decent solution in D. I said *non* virtual MI above.. But virtual inheritance is C++'s way to resolve the diamond problem. I don't think it is related to our discussion in any way. This gets more and more complicated - Like I said before, I feel that renaming has easier to understand semantics. As an exercise, I'm working on a mixin that will allow to subtype a class and rename/override its virtual functions like this: class FlippingBlipper { mixin Subclass!(Flipper, nameCollision, foo) flipper; this() { flipper.construct(...); } void foo() { ... } } Save for some bugs in the compiler, it should work reasonably well. Or maybe not. I think 'alias this' is a powerful feature. Given the constraints like easy for the compiler writer to implement and we have many other things to do, I doubt traits or something like that will be or needs to be in the language. Alias this is powerful black magic. being powerful doesn't make it any less dark. Could you explain why it is dark?
Re: Multiple subtyping with alias this and nested classes
On Sun, 04 Oct 2009 12:31:08 -0400, Yigal Chripun yigal...@gmail.com wrote: Max Samukha Wrote: I see. What you want is non-virtual MI. I don't think that allowing the derived class to have two distinct implementations for the same function prototype is a good idea. Eiffel handles this by giving the programmer controls to select features and rename them in the derived class which I think is better. // hypothetical syntax example class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; // rename the inherited interface functions alias IBlipper.nameCollision boo; alias IFilpper.nameCollision foo; // implement the now two distinct functions void foo() { F.nameCollision(); } void boo() { B.nameCollision(); } } you can further subtype and the derived foo boo will override the respective interfaces. Yes, but what if nameCollision is a virtual function called somewhere in the template mixin? Your example has effectively removed the virtuality. it doesn't remove virtuality. Virtual functions are stored as pointers in the vtable. with my suggested solution the idea is that the same pointer in the vtable gets a new name in the derived class. when you mixin the template into the derived class the compiler would resolve nameCollision to the new name foo because of the renaming rule in the derived class. Ok, I still cannot see how the compiler can reliably determine that IFlipper.nameCollision is implemented by Flipper and not by Blipper and call the correct override when flip is called. Should the compiler deduce that from F.nameCollision? If yes, what about: void foo() { B.nameCollision; F.nameCollision; } ? Or should it decide based on the fact that Flipper contains the 'flip' function that implements IFlipper.flip? If yes, then what if the interfaces had nothing more than the 'nameCollision' functions? I don't think I want non virtual MI in D since it is more trouble than it's worth. but *if* we discuss this, I think my suggested semantics are simpler. The syntax probably can be much better but that's a secondary issue IMO. It's unrelated to virtual MI. See Sergey Gromov's post. We are discussing this only because it's a real world problem that has no decent solution in D. with my design: class Foo : FlippingBlipper { override foo ... override bar ... } IFlipper obj = new Foo; obj.nameCollision; // will call Foo.bar I don't think that's possible with your design. I'm not claiming it's my design. Andrei is the author. And yes, it's possible in a number of ways. One is: class BlippingFlipper { class Flipper_ : Flipper { override void nameCollision() { foo(); } final void super_nameCollision() { super.nameCollision; } } this() { flipper = new Flipper_; } Flipper_ flipper; alias flipper this; void foo() { flipper.super_nameCollision; } } class Foo : BlippingFlipper { override void foo() {} } (Wordy but still possible. Can be made easier on the eye with a helper mixin) I agree that possibility to implement renamed interface methods AND explicit interface implementation would solve the problem of name collisions. But it doesn't solve the problem of subtyping structs and built-in types. besides, alias this is a hack. a better mechanism would be to have compile-time inheritance, IMO. I think 'alias this' is a powerful feature. Given the constraints like easy for the compiler writer to implement and we have many other things to do, I doubt traits or something like that will be or needs to be in the language.
Re: Multiple subtyping with alias this and nested classes
On 05/10/2009 12:19, Max Samukha wrote: On Sun, 04 Oct 2009 12:31:08 -0400, Yigal Chripunyigal...@gmail.com wrote: Max Samukha Wrote: I see. What you want is non-virtual MI. I don't think that allowing the derived class to have two distinct implementations for the same function prototype is a good idea. Eiffel handles this by giving the programmer controls to select features and rename them in the derived class which I think is better. // hypothetical syntax example class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; // rename the inherited interface functions alias IBlipper.nameCollision boo; alias IFilpper.nameCollision foo; // implement the now two distinct functions void foo() { F.nameCollision(); } void boo() { B.nameCollision(); } } you can further subtype and the derived foo boo will override the respective interfaces. Yes, but what if nameCollision is a virtual function called somewhere in the template mixin? Your example has effectively removed the virtuality. it doesn't remove virtuality. Virtual functions are stored as pointers in the vtable. with my suggested solution the idea is that the same pointer in the vtable gets a new name in the derived class. when you mixin the template into the derived class the compiler would resolve nameCollision to the new name foo because of the renaming rule in the derived class. Ok, I still cannot see how the compiler can reliably determine that IFlipper.nameCollision is implemented by Flipper and not by Blipper and call the correct override when flip is called. Should the compiler deduce that from F.nameCollision? If yes, what about: void foo() { B.nameCollision; F.nameCollision; } ? Or should it decide based on the fact that Flipper contains the 'flip' function that implements IFlipper.flip? If yes, then what if the interfaces had nothing more than the 'nameCollision' functions? I see you want to discuss the details of the renaming mechanism, while I just talked about the general idea itself until now. we have two cases: regular and mixins. for case a it's simple, the class itself lists the renames: Interface A { void foo(); } Interface B { void foo(); } class C : A, B { alias A.foo func1; // or similar syntax to mark the renaming alias B.foo func2; // ditto override void func1() {...} // C.func1 overrides A.foo override void func2() {...} // C.func2 overrides B.foo } case 2, mixins: I think some sort of annotations by the programmer is needed. class C : A, B { alias A.foo func1; // or similar syntax to mark the renaming alias B.foo func2; // ditto // hypothetical syntax to connect mixins to interfaces // the compiler will apply the rename rules of this class assuming that // any references to foo in ImplA are A.foo and will be renamed to // func1 in C // if the mixin explicitly specifies the interface (e.g B.foo) than the // compiler already knows what to map this to. mixin ImplA A; mixin ImplB B; } btw, this all can be done in a much simpler way with (hygienic) AST Macros. I don't think I want non virtual MI in D since it is more trouble than it's worth. but *if* we discuss this, I think my suggested semantics are simpler. The syntax probably can be much better but that's a secondary issue IMO. It's unrelated to virtual MI. See Sergey Gromov's post. We are discussing this only because it's a real world problem that has no decent solution in D. I said *non* virtual MI above.. with my design: class Foo : FlippingBlipper { override foo ... override bar ... } IFlipper obj = new Foo; obj.nameCollision; // will call Foo.bar I don't think that's possible with your design. I'm not claiming it's my design. Andrei is the author. And yes, it's possible in a number of ways. One is: class BlippingFlipper { class Flipper_ : Flipper { override void nameCollision() { foo(); } final void super_nameCollision() { super.nameCollision; } } this() { flipper = new Flipper_; } Flipper_ flipper; alias flipper this; void foo() { flipper.super_nameCollision; } } class Foo : BlippingFlipper { override void foo() {} } (Wordy but still possible. Can be made easier on the eye with a helper mixin) This gets more and more complicated - Like I said before, I feel that renaming has easier to understand semantics. I agree that possibility to implement renamed interface methods AND explicit interface implementation would solve the problem of name collisions. But it doesn't solve the problem of subtyping structs and built-in types. the problem with explicit interface implementation as discussed in another thread is that the implementations will become hidden. class C: A, B { override void A.foo () { ... } override void B.foo () { ... } } C obj = new C; obj.foo(); // error class D : C { ... } what happens in class D? Can I override the functions there as well? how? you do not need explicit interface
Re: Multiple subtyping with alias this and nested classes
Yigal Chripun wrote: I think 'alias this' is a powerful feature. Given the constraints like easy for the compiler writer to implement and we have many other things to do, I doubt traits or something like that will be or needs to be in the language. Alias this is powerful black magic. being powerful doesn't make it any less dark. So how does this work? Alias this was meant very clearly for allowing subtyping. Conversely, using it for subtyping is precisely how it was meant to be used. How exactly did you decide it was a hack or black magic or whatever? Andrei
Re: Multiple subtyping with alias this and nested classes
On 06/10/2009 02:15, Andrei Alexandrescu wrote: Yigal Chripun wrote: I think 'alias this' is a powerful feature. Given the constraints like easy for the compiler writer to implement and we have many other things to do, I doubt traits or something like that will be or needs to be in the language. Alias this is powerful black magic. being powerful doesn't make it any less dark. So how does this work? Alias this was meant very clearly for allowing subtyping. Conversely, using it for subtyping is precisely how it was meant to be used. How exactly did you decide it was a hack or black magic or whatever? Andrei D already has syntax for sub-typing reference types and alias this introduces a completely different syntax doing the same for value types which is bad human interface IMO. it also mixes two concepts - sub-typing and opImplicitCast (as i recall, this is done by alias this to a function) we discussed this in the past already and IIRC you agreed with me about implementing compile time inheritance for structs which I feel is much cleaner and more consistent with the existing syntax of interfaces.
Re: Multiple subtyping with alias this and nested classes
On Sat, 03 Oct 2009 16:30:11 -0600, Rainer Deyke rain...@eldwood.com wrote: Max Samukha wrote: The above sucks because we can't specify which nameCollision gets implemented by which mixin. In current D, nameCollision of both interfaces is implemented by Flipper. I don't think that being able to define multiple separate functions with the same name and the same signature is a necessary feature of multiple inheritance, or even a particularly well thought-out one. It is not always a question of choice. For example, when you are not the designer of base types you want to subtype. Python is an example of a language without this feature, and multiple inheritance is very common in Python. One of the reasons Python's MI is not recommended is its reliance on naming conventions. There is a note in some Python (version unknown) docs: It is clear that indiscriminate use of multiple inheritance is a maintenance nightmare, given the reliance in Python on conventions to avoid accidental name conflicts. (http://www.python.org/doc/1.5.1p1/tut/multiple.html)
Re: Multiple subtyping with alias this and nested classes
On Sat, 03 Oct 2009 21:19:05 +0300, Max Samukha spam...@d-coding.com wrote: We would probably be able to overcome the limitation if and when explicit interface instantiation is implemented: should be explicit interface implementation is supported. Sorry.
Re: Multiple subtyping with alias this and nested classes
On Sun, 04 Oct 2009 00:10:30 +0200, Yigal Chripun yigal...@gmail.com wrote: class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; alias F.nameCollision nameCollision; } The problem is that IBlipper.nameCollision is totally unrelated to IFlipper.nameCollision (for example, if the interfaces/mixins come from third-party libraries, whose developers don't know or care about each other, e.g. Tango/Phobos :P). That's why either nameCollision must have its own implementation. In current D: auto fb = new FlippingBlipper; IFlipper f = fb; IBlipper b = fb; f.nameCollision; b.nameCollision; Both calls are dispatched to the same implementation (the one provided by Flipper template), which is incorrect and undesirable. I wonder if the following would work: class FlippingBlipper : IBlipper, IFilpper { mixin Flipper IFilpper; mixin Blipper IBlipper; } I don't think so.
Re: Multiple subtyping with alias this and nested classes
Max Samukha Wrote: On Sun, 04 Oct 2009 00:10:30 +0200, Yigal Chripun yigal...@gmail.com wrote: class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; alias F.nameCollision nameCollision; } The problem is that IBlipper.nameCollision is totally unrelated to IFlipper.nameCollision (for example, if the interfaces/mixins come from third-party libraries, whose developers don't know or care about each other, e.g. Tango/Phobos :P). That's why either nameCollision must have its own implementation. In current D: auto fb = new FlippingBlipper; IFlipper f = fb; IBlipper b = fb; f.nameCollision; b.nameCollision; Both calls are dispatched to the same implementation (the one provided by Flipper template), which is incorrect and undesirable. I wonder if the following would work: class FlippingBlipper : IBlipper, IFilpper { mixin Flipper IFilpper; mixin Blipper IBlipper; } I don't think so. I see. What you want is non-virtual MI. I don't think that allowing the derived class to have two distinct implementations for the same function prototype is a good idea. Eiffel handles this by giving the programmer controls to select features and rename them in the derived class which I think is better. // hypothetical syntax example class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; // rename the inherited interface functions alias IBlipper.nameCollision boo; alias IFilpper.nameCollision foo; // implement the now two distinct functions void foo() { F.nameCollision(); } void boo() { B.nameCollision(); } } you can further subtype and the derived foo boo will override the respective interfaces.
Re: Multiple subtyping with alias this and nested classes
On Sun, 04 Oct 2009 06:31:25 -0400, Yigal Chripun yigal...@gmail.com wrote: Max Samukha Wrote: On Sun, 04 Oct 2009 00:10:30 +0200, Yigal Chripun yigal...@gmail.com wrote: class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; alias F.nameCollision nameCollision; } The problem is that IBlipper.nameCollision is totally unrelated to IFlipper.nameCollision (for example, if the interfaces/mixins come from third-party libraries, whose developers don't know or care about each other, e.g. Tango/Phobos :P). That's why either nameCollision must have its own implementation. In current D: auto fb = new FlippingBlipper; IFlipper f = fb; IBlipper b = fb; f.nameCollision; b.nameCollision; Both calls are dispatched to the same implementation (the one provided by Flipper template), which is incorrect and undesirable. I wonder if the following would work: class FlippingBlipper : IBlipper, IFilpper { mixin Flipper IFilpper; mixin Blipper IBlipper; } I don't think so. I see. What you want is non-virtual MI. I don't think that allowing the derived class to have two distinct implementations for the same function prototype is a good idea. Eiffel handles this by giving the programmer controls to select features and rename them in the derived class which I think is better. // hypothetical syntax example class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; // rename the inherited interface functions alias IBlipper.nameCollision boo; alias IFilpper.nameCollision foo; // implement the now two distinct functions void foo() { F.nameCollision(); } void boo() { B.nameCollision(); } } you can further subtype and the derived foo boo will override the respective interfaces. Yes, but what if nameCollision is a virtual function called somewhere in the template mixin? Your example has effectively removed the virtuality. If your mixin template contains unimplemented or partially implemented virtual functions (for example, in case of an abstract base type), you have to derive another class to (re)implement them. Ok, I'm not arguing that mixins+interfaces cannot be used to emulate multiple subtyping. I'm arguing it has problems that may force one to resort to horrible hacks. How is it better than the solution provided by 'alias this' and nested classes? 'alias this' doesn't require mixin templates, handles name conflicts nicely, allows subtyping of value types, allows (re)implementing base functions directly in the subtype (using nested classes). BTW, your example rewriten with 'alias this' looks cleaner, IMHO: class Flipper { ... } class Blipper { ... } class FlippingBlipper { Flipper flipper; Blipper blipper; this { blipper = new Blipper; flipper = new Flipper; } alias this flipper; alias this blipper; void foo() { blipper.nameCollision; } void bar() { flipper.nameCollision; } } No interfaces, no templates, no renaming. Problem solved. Almost. We have to be able to instantiate classes in-place to avoid unnecessary allocations.
Re: Multiple subtyping with alias this and nested classes
On Sun, 04 Oct 2009 15:26:53 +0300, Max Samukha spam...@d-coding.com wrote: BTW, your example rewriten with 'alias this' looks cleaner, IMHO: class Flipper { ... } class Blipper { ... } class FlippingBlipper { Flipper flipper; Blipper blipper; this { blipper = new Blipper; flipper = new Flipper; } alias this flipper; alias this blipper; void foo() { blipper.nameCollision; } void bar() { flipper.nameCollision; } } Even cleaner: class FlippingBlipper : Flipper { Blipper blipper; this { blipper = new Blipper; } alias this blipper; void foo() { blipper.nameCollision; } void bar() { nameCollision; } // will it call Flipper.nameCollision? }
Re: Multiple subtyping with alias this and nested classes
Sun, 04 Oct 2009 00:10:30 +0200, Yigal Chripun wrote: interface IBlipper { void blip(); void nameCollision(); } template Blipper() { void blip() {} void nameCollision() {} } interface IFlipper { void flip(); void nameCollision(); } template Flipper() { void flip() {} void nameCollision() {} } interfaces implement virtual MI, so FlippingBlipper must implement one nameCollision which is shared by both interfaces. That's not correct if you're talking about virtual MI in C++. There, you'd have to create a common root for the virtual inheritance to actually work: class INameCollider { public: virtual void nameCollision() = 0; }; class IFlipper: public virtual INameCollider { public: virtual void flip() = 0; }; class IBlipper: public virtual INameCollider { public: virtual void blip() = 0; }; class FlippingBlipper: public IFlipper, public IBlipper { public: // Contains single, common nameCollision() virtual void nameCollision() {} virtual void flip() {} virtual void blip() {} }; Otherwise, if IFlipper and IBlipper are unrelated, you have two separate nameCollision() functions which you must disambiguate as IFlipper::nameCollision() and IBlipper::nameCollision() both when defining and when calling via a FlippingBlipper instance.
Re: Multiple subtyping with alias this and nested classes
Max Samukha Wrote: I see. What you want is non-virtual MI. I don't think that allowing the derived class to have two distinct implementations for the same function prototype is a good idea. Eiffel handles this by giving the programmer controls to select features and rename them in the derived class which I think is better. // hypothetical syntax example class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; // rename the inherited interface functions alias IBlipper.nameCollision boo; alias IFilpper.nameCollision foo; // implement the now two distinct functions void foo() { F.nameCollision(); } void boo() { B.nameCollision(); } } you can further subtype and the derived foo boo will override the respective interfaces. Yes, but what if nameCollision is a virtual function called somewhere in the template mixin? Your example has effectively removed the virtuality. it doesn't remove virtuality. Virtual functions are stored as pointers in the vtable. with my suggested solution the idea is that the same pointer in the vtable gets a new name in the derived class. when you mixin the template into the derived class the compiler would resolve nameCollision to the new name foo because of the renaming rule in the derived class. If your mixin template contains unimplemented or partially implemented virtual functions (for example, in case of an abstract base type), you have to derive another class to (re)implement them. Ok, I'm not arguing that mixins+interfaces cannot be used to emulate multiple subtyping. I'm arguing it has problems that may force one to resort to horrible hacks. How is it better than the solution provided by 'alias this' and nested classes? 'alias this' doesn't require mixin templates, handles name conflicts nicely, allows subtyping of value types, allows (re)implementing base functions directly in the subtype (using nested classes). I don't think I want non virtual MI in D since it is more trouble than it's worth. but *if* we discuss this, I think my suggested semantics are simpler. The syntax probably can be much better but that's a secondary issue IMO. BTW, your example rewriten with 'alias this' looks cleaner, IMHO: class Flipper { ... } class Blipper { ... } class FlippingBlipper { Flipper flipper; Blipper blipper; this { blipper = new Blipper; flipper = new Flipper; } alias this flipper; alias this blipper; void foo() { blipper.nameCollision; } void bar() { flipper.nameCollision; } } No interfaces, no templates, no renaming. Problem solved. Almost. We have to be able to instantiate classes in-place to avoid unnecessary allocations. with my design: class Foo : FlippingBlipper { override foo ... override bar ... } IFlipper obj = new Foo; obj.nameCollision; // will call Foo.bar I don't think that's possible with your design. besides, alias this is a hack. a better mechanism would be to have compile-time inheritance, IMO.
Re: Multiple subtyping with alias this and nested classes
Andrei Alexandrescu, el 2 de octubre a las 19:10 me escribiste: Leandro Lucarella wrote: We might have very different taste, but I find that a little... horrible. What do you have against mixins? I think you're trying to use D as C++ :) If mixins work better, all the better. How would you use them to achieve multiple inheritance? Don't design with multiple inheritance in mind, use interfaces + mixins for common functionality instead. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ -- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) -- Bermú con papafritas y good show!
Re: Multiple subtyping with alias this and nested classes
Leandro Lucarella wrote: Andrei Alexandrescu, el 2 de octubre a las 19:10 me escribiste: Leandro Lucarella wrote: We might have very different taste, but I find that a little... horrible. What do you have against mixins? I think you're trying to use D as C++ :) If mixins work better, all the better. How would you use them to achieve multiple inheritance? Don't design with multiple inheritance in mind, use interfaces + mixins for common functionality instead. But you're just saying it. I think you'd agree I wouldn't just follow that dogma noncritically just because you told me what to do. I don't think many people design with multiple inheritance in mind. They design aiming at a good design. In my experience, some designs can make gainful use of multiple inheritance of classes, and some of my best designs do use multiple inheritance simply because it was the best tool for the job. Scala supports that with mixins, D supports that with multiple subtyping. Andrei
Re: Multiple subtyping with alias this and nested classes
Andrei Alexandrescu, el 3 de octubre a las 11:23 me escribiste: Leandro Lucarella wrote: Andrei Alexandrescu, el 2 de octubre a las 19:10 me escribiste: Leandro Lucarella wrote: We might have very different taste, but I find that a little... horrible. What do you have against mixins? I think you're trying to use D as C++ :) If mixins work better, all the better. How would you use them to achieve multiple inheritance? Don't design with multiple inheritance in mind, use interfaces + mixins for common functionality instead. But you're just saying it. I think you'd agree I wouldn't just follow that dogma noncritically just because you told me what to do. No, because the language is designed to do that AFAIK, so it will be much easier and clear (for who writes the code and who reads it). I think you hack with alias this is more obscure (we might be hitting personal taste here, I grant you that). I don't think many people design with multiple inheritance in mind. They design aiming at a good design. But you always have to take into account the tools you have when designing. What's the point of designing a perfect bridge assuming you have a material that doesn't exist? Of course you can do that, but when you hit reality, you'll have to hack your design to fit your real tools. So you can design something that looks like multiple-inheritance, because it's easier (or nicer) to do so. But when you want to put that in reality, you have to choose what tool to use. In C++ you probably want to use MI (because the language has a good support for it), but in D you probably want to use interfaces + mixins (because the language has good support for it). Of course you can even implement it in C, or even assembly; you can implement it as in C in C++ or D too, but it would be harder and more obscure. In my experience, some designs can make gainful use of multiple inheritance of classes, and some of my best designs do use multiple inheritance simply because it was the best tool for the job. Sure, the problem comes when the language don't support MI ;) So, there we are, you have D, which doesn't support MI per se, you have to hack it. You can do it with the nested-inherited-classes+alias-this hack, or by using interfaces+mixins. We agree at least that you have the same result with both right? Then, I guess is just a matter of taste. I simply find much more obscure and complex the nested-inherited-classes+alias-this hack than interfaces+mixins :) Scala supports that with mixins, D supports that with multiple subtyping. I don't know what you mean about multiple subtyping. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ -- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) -- I am so psychosomatic it makes me sick just thinking about it! -- George Constanza
Re: Multiple subtyping with alias this and nested classes
Leandro Lucarella wrote: Andrei Alexandrescu, el 3 de octubre a las 11:23 me escribiste: Leandro Lucarella wrote: Andrei Alexandrescu, el 2 de octubre a las 19:10 me escribiste: Leandro Lucarella wrote: We might have very different taste, but I find that a little... horrible. What do you have against mixins? I think you're trying to use D as C++ :) If mixins work better, all the better. How would you use them to achieve multiple inheritance? Don't design with multiple inheritance in mind, use interfaces + mixins for common functionality instead. But you're just saying it. I think you'd agree I wouldn't just follow that dogma noncritically just because you told me what to do. No, because the language is designed to do that AFAIK, so it will be much easier and clear (for who writes the code and who reads it). I think you hack with alias this is more obscure (we might be hitting personal taste here, I grant you that). Alias this was introduced purposedly to allow multiple subtyping. Until yesterday, however, I hadn't realized how much nested classes help with that. Even before that I wasn't worried, since MI designs are not as frequent as SI designs. I don't think many people design with multiple inheritance in mind. They design aiming at a good design. But you always have to take into account the tools you have when designing. What's the point of designing a perfect bridge assuming you have a material that doesn't exist? Of course you can do that, but when you hit reality, you'll have to hack your design to fit your real tools. So you can design something that looks like multiple-inheritance, because it's easier (or nicer) to do so. But when you want to put that in reality, you have to choose what tool to use. In C++ you probably want to use MI (because the language has a good support for it), but in D you probably want to use interfaces + mixins (because the language has good support for it). Of course you can even implement it in C, or even assembly; you can implement it as in C in C++ or D too, but it would be harder and more obscure. In my experience, some designs can make gainful use of multiple inheritance of classes, and some of my best designs do use multiple inheritance simply because it was the best tool for the job. Sure, the problem comes when the language don't support MI ;) So, there we are, you have D, which doesn't support MI per se, you have to hack it. You can do it with the nested-inherited-classes+alias-this hack, or by using interfaces+mixins. We agree at least that you have the same result with both right? Then, I guess is just a matter of taste. I simply find much more obscure and complex the nested-inherited-classes+alias-this hack than interfaces+mixins :) I don't see using a nested class (or any class) with alias this as a hack. It's the way the whole thing is supposed to work in the first place. Scala supports that with mixins, D supports that with multiple subtyping. I don't know what you mean about multiple subtyping. You subtype once by using inheritance, and then some more by using alias this. Andrei
Re: Multiple subtyping with alias this and nested classes
Andrei Alexandrescu, el 3 de octubre a las 12:03 me escribiste: So, there we are, you have D, which doesn't support MI per se, you have to hack it. You can do it with the nested-inherited-classes+alias-this hack, or by using interfaces+mixins. We agree at least that you have the same result with both right? Then, I guess is just a matter of taste. I simply find much more obscure and complex the nested-inherited-classes+alias-this hack than interfaces+mixins :) I don't see using a nested class (or any class) with alias this as a hack. It's the way the whole thing is supposed to work in the first place. Ok, then, I just find it ugly and unnecessary since you can do the same with interfaces+mixins. It's just a matter of personal preferences (as I said in my first mail), there is no point on arguing about it. =) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ -- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) -- I'll take a quiet life, a handshake of carbon monoxide, with no alarms and no surprises, no alarms and no surprises.
Re: Multiple subtyping with alias this and nested classes
On Sat, 03 Oct 2009 13:52:51 -0300, Leandro Lucarella wrote: Scala supports that with mixins, D supports that with multiple subtyping. I don't know what you mean about multiple subtyping. I have also not seen the specs for this feature. How does multiple subtyping work exactly in D? Does it have exactly the same semantics as using interfaces + mixing in the traits? Why was the 'alias foo this' chosen if you are also planning to add support for Scala like traits (some other thread here recently discussed this). Andrei, you probably know how Scala chooses the overrides and overloads when traits have conflicts. How does D handle this?
Re: Multiple subtyping with alias this and nested classes
On Sat, 3 Oct 2009 14:11:37 -0300, Leandro Lucarella llu...@gmail.com wrote: Ok, then, I just find it ugly and unnecessary since you can do the same with interfaces+mixins. Actually, you can't. Consider: interface IBlipper { void blip(); void nameCollision(); } template Blipper() { void blip() {} void nameCollision() {} } interface IFlipper { void flip(); void nameCollision(); } template Flipper() { void flip() {} void nameCollision() {} } class FlippingBlipper : IBlipper, IFilpper { mixin Flipper; mixin Blipper; } The above sucks because we can't specify which nameCollision gets implemented by which mixin. In current D, nameCollision of both interfaces is implemented by Flipper. We would probably be able to overcome the limitation if and when explicit interface instantiation is implemented: template Blipper() { void IBlipper.blip() {} void IBlipper.nameCollision() {} } template Flipper() { void IFlipper.flip() {} void IFlipper.nameCollision() {} } Until then, mixin + interface just doesn't work. It's just a matter of personal preferences (as I said in my first mail), there is no point on arguing about it. =)
Re: Multiple subtyping with alias this and nested classes
language_fan wrote: On Sat, 03 Oct 2009 13:52:51 -0300, Leandro Lucarella wrote: Scala supports that with mixins, D supports that with multiple subtyping. I don't know what you mean about multiple subtyping. I have also not seen the specs for this feature. How does multiple subtyping work exactly in D? The feature is very much in the works. I gave a basic example for two types. Unfortunately at the moment only one alias this declaration is allowed. The plan is to allow any number. Does it have exactly the same semantics as using interfaces + mixing in the traits? No. Why was the 'alias foo this' chosen if you are also planning to add support for Scala like traits (some other thread here recently discussed this). Currently there are no plans to add support for Scala-like traits. Andrei, you probably know how Scala chooses the overrides and overloads when traits have conflicts. How does D handle this? Walter and I are working the kinks of name lookup. If you have ideas, please share. Andrei
Re: Multiple subtyping with alias this and nested classes
language_fan wrote: On Sat, 03 Oct 2009 13:52:51 -0300, Leandro Lucarella wrote: Scala supports that with mixins, D supports that with multiple subtyping. I don't know what you mean about multiple subtyping. I have also not seen the specs for this feature. How does multiple subtyping work exactly in D? The feature is very much in the works. I gave a basic example for two types. Unfortunately at the moment only one alias this declaration is allowed. The plan is to allow any number. Does it have exactly the same semantics as using interfaces + mixing in the traits? No. Why was the 'alias foo this' chosen if you are also planning to add support for Scala like traits (some other thread here recently discussed this). Currently there are no plans to add support for Scala-like traits. Andrei, you probably know how Scala chooses the overrides and overloads when traits have conflicts. How does D handle this? Walter and I are working the kinks of name lookup. If you have ideas, please share. Andrei
Re: Multiple subtyping with alias this and nested classes
On 03/10/2009 20:19, Max Samukha wrote: On Sat, 3 Oct 2009 14:11:37 -0300, Leandro Lucarella llu...@gmail.com wrote: Ok, then, I just find it ugly and unnecessary since you can do the same with interfaces+mixins. Actually, you can't. Consider: interface IBlipper { void blip(); void nameCollision(); } template Blipper() { void blip() {} void nameCollision() {} } interface IFlipper { void flip(); void nameCollision(); } template Flipper() { void flip() {} void nameCollision() {} } class FlippingBlipper : IBlipper, IFilpper { mixin Flipper; mixin Blipper; } The above sucks because we can't specify which nameCollision gets implemented by which mixin. In current D, nameCollision of both interfaces is implemented by Flipper. We would probably be able to overcome the limitation if and when explicit interface instantiation is implemented: template Blipper() { void IBlipper.blip() {} void IBlipper.nameCollision() {} } template Flipper() { void IFlipper.flip() {} void IFlipper.nameCollision() {} } Until then, mixin + interface just doesn't work. It's just a matter of personal preferences (as I said in my first mail), there is no point on arguing about it. =) interfaces implement virtual MI, so FlippingBlipper must implement one nameCollision which is shared by both interfaces. however you can give names to mixins so that you could choose which implementation to use for that and also have both implementations. class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; alias F.nameCollision nameCollision; } I wonder if the following would work: class FlippingBlipper : IBlipper, IFilpper { mixin Flipper IFilpper; mixin Blipper IBlipper; }
Re: Multiple subtyping with alias this and nested classes
Max Samukha wrote: The above sucks because we can't specify which nameCollision gets implemented by which mixin. In current D, nameCollision of both interfaces is implemented by Flipper. I don't think that being able to define multiple separate functions with the same name and the same signature is a necessary feature of multiple inheritance, or even a particularly well thought-out one. Python is an example of a language without this feature, and multiple inheritance is very common in Python. -- Rainer Deyke - rain...@eldwood.com
Multiple subtyping with alias this and nested classes
I just realized that nested classes work so well with alias this, you'd think it was an evil plot all along. It wasn't, but I'm happy about the coincidence. Here's how to effect multiple subtyping in D very effectively: import std.stdio; class Base1 { void fun() { writeln(Base.fun); } } class Base2 { void gun() { writeln(Base.fun); } } class Multiple : Base1 { // Override method in Base1 override void fun() { writeln(Multiple.fun); } // Override method in Base2 class MyBase2 : Base2 { override void gun() { writeln(Multiple.gun); } } // Effect multiple subtyping Base2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } void main() { auto obj = new Multiple; Base1 obj1 = obj; obj1.fun(); Base2 obj2 = obj; obj2.gun(); } The program above segfaults because somehow obj2 is null. That is a bug I just reported. For now, you can replace obj2.gun() with obj.gun() to make things work. When we first introduced alias this, I knew multiple subtyping was possible. I didn't expect it to dovetail so nicely with nested classes. Andrei
Re: Multiple subtyping with alias this and nested classes
Fri, 02 Oct 2009 13:00:05 -0500, Andrei Alexandrescu thusly wrote: I just realized that nested classes work so well with alias this, you'd think it was an evil plot all along. It wasn't, but I'm happy about the coincidence. Here's how to effect multiple subtyping in D very effectively: import std.stdio; class Base1 { void fun() { writeln(Base.fun); } } class Base2 { void gun() { writeln(Base.fun); } } class Multiple : Base1 { override void fun() { writeln(Multiple.fun); } class MyBase2 : Base2 { override void gun() { writeln(Multiple.gun); } } // Effect multiple subtyping Base2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } I do not get why didn't you just use the 'import' keyword here instead of alias, since what you are basically doing is importing the symbols from one scope to another. It would seem a perfect generalization of import to also include cases where 'with' is currently used and also alias. The use of the term 'alias' is somewhat confusing.
Re: Multiple subtyping with alias this and nested classes
language_fan wrote: Fri, 02 Oct 2009 13:00:05 -0500, Andrei Alexandrescu thusly wrote: I just realized that nested classes work so well with alias this, you'd think it was an evil plot all along. It wasn't, but I'm happy about the coincidence. Here's how to effect multiple subtyping in D very effectively: import std.stdio; class Base1 { void fun() { writeln(Base.fun); } } class Base2 { void gun() { writeln(Base.fun); } } class Multiple : Base1 { override void fun() { writeln(Multiple.fun); } class MyBase2 : Base2 { override void gun() { writeln(Multiple.gun); } } // Effect multiple subtyping Base2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } I do not get why didn't you just use the 'import' keyword here instead of alias, since what you are basically doing is importing the symbols from one scope to another. It would seem a perfect generalization of import to also include cases where 'with' is currently used and also alias. The use of the term 'alias' is somewhat confusing. Well if we did use 'import' people would have asked why we don't use 'alias' because that's much closer to what really happens. Note that the feature does not only import symbols from one scope to another. It just allows you to substitute some expression when someone tries to use this under another type. Andrei
Re: Multiple subtyping with alias this and nested classes
On Fri, 02 Oct 2009 13:00:05 -0500, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: I just realized that nested classes work so well with alias this, you'd think it was an evil plot all along. It wasn't, but I'm happy about the coincidence. Here's how to effect multiple subtyping in D very effectively: import std.stdio; class Base1 { void fun() { writeln(Base.fun); } } class Base2 { void gun() { writeln(Base.fun); } } class Multiple : Base1 { // Override method in Base1 override void fun() { writeln(Multiple.fun); } // Override method in Base2 class MyBase2 : Base2 { override void gun() { writeln(Multiple.gun); } } // Effect multiple subtyping Base2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } void main() { auto obj = new Multiple; Base1 obj1 = obj; obj1.fun(); Base2 obj2 = obj; obj2.gun(); } The program above segfaults because somehow obj2 is null. That is a bug I just reported. For now, you can replace obj2.gun() with obj.gun() to make things work. When we first introduced alias this, I knew multiple subtyping was possible. I didn't expect it to dovetail so nicely with nested classes. Andrei Neat! But what if there is Base3? Is it supposed to be subtyped like this: class Base3 { void run() {} } class Multiple : Base1 { // Override method in Base1 override void fun() { writeln(Multiple.fun); } // Override method in Base2 class MyBase2 : Base2 { class MyBase3 : Base3 { override void run() { writeln(Multiple.run); } } MyBase3 _base3; this() { _base3 = new MyBase3; } alias _base3 this; override void gun() { writeln(Multiple.gun); } } // Effect multiple subtyping MyBase2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } ? Note that there is an additional level of indirection per each subtype: auto m = new Multiple; m.run is unrolled to m._base2._base3.run
Re: Multiple subtyping with alias this and nested classes
On Fri, 02 Oct 2009 21:41:54 +0300, Max Samukha spam...@d-coding.com wrote: Note that there is an additional level of indirection per each subtype: subtype = subtyped type
Re: Multiple subtyping with alias this and nested classes
Max Samukha wrote: On Fri, 02 Oct 2009 13:00:05 -0500, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: I just realized that nested classes work so well with alias this, you'd think it was an evil plot all along. It wasn't, but I'm happy about the coincidence. Here's how to effect multiple subtyping in D very effectively: import std.stdio; class Base1 { void fun() { writeln(Base.fun); } } class Base2 { void gun() { writeln(Base.fun); } } class Multiple : Base1 { // Override method in Base1 override void fun() { writeln(Multiple.fun); } // Override method in Base2 class MyBase2 : Base2 { override void gun() { writeln(Multiple.gun); } } // Effect multiple subtyping Base2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } void main() { auto obj = new Multiple; Base1 obj1 = obj; obj1.fun(); Base2 obj2 = obj; obj2.gun(); } The program above segfaults because somehow obj2 is null. That is a bug I just reported. For now, you can replace obj2.gun() with obj.gun() to make things work. When we first introduced alias this, I knew multiple subtyping was possible. I didn't expect it to dovetail so nicely with nested classes. Andrei Neat! But what if there is Base3? Is it supposed to be subtyped like this: class Base3 { void run() {} } class Multiple : Base1 { // Override method in Base1 override void fun() { writeln(Multiple.fun); } // Override method in Base2 class MyBase2 : Base2 { class MyBase3 : Base3 { override void run() { writeln(Multiple.run); } } MyBase3 _base3; this() { _base3 = new MyBase3; } alias _base3 this; override void gun() { writeln(Multiple.gun); } } // Effect multiple subtyping MyBase2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } ? Note that there is an additional level of indirection per each subtype: auto m = new Multiple; m.run is unrolled to m._base2._base3.run Multiple alias this declarations must be allowed. Andrei
Re: Multiple subtyping with alias this and nested classes
Andrei Alexandrescu, el 2 de octubre a las 13:00 me escribiste: I just realized that nested classes work so well with alias this, you'd think it was an evil plot all along. It wasn't, but I'm happy about the coincidence. Here's how to effect multiple subtyping in D very effectively: import std.stdio; class Base1 { void fun() { writeln(Base.fun); } } class Base2 { void gun() { writeln(Base.fun); } } class Multiple : Base1 { // Override method in Base1 override void fun() { writeln(Multiple.fun); } // Override method in Base2 class MyBase2 : Base2 { override void gun() { writeln(Multiple.gun); } } // Effect multiple subtyping Base2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } void main() { auto obj = new Multiple; Base1 obj1 = obj; obj1.fun(); Base2 obj2 = obj; obj2.gun(); } The program above segfaults because somehow obj2 is null. That is a bug I just reported. For now, you can replace obj2.gun() with obj.gun() to make things work. When we first introduced alias this, I knew multiple subtyping was possible. I didn't expect it to dovetail so nicely with nested classes. We might have very different taste, but I find that a little... horrible. What do you have against mixins? I think you're trying to use D as C++ :) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ -- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) -- EL PRIMER MONITO DEL MILENIO... -- Crónica TV
Re: Multiple subtyping with alias this and nested classes
Fri, 02 Oct 2009 19:35:55 -0300, Leandro Lucarella thusly wrote: We might have very different taste, but I find that a little... horrible. What do you have against mixins? I think you're trying to use D as C++ :) So basically the diamond problem is again implementable in D, yay?
Re: Multiple subtyping with alias this and nested classes
Leandro Lucarella wrote: We might have very different taste, but I find that a little... horrible. What do you have against mixins? I think you're trying to use D as C++ :) If mixins work better, all the better. How would you use them to achieve multiple inheritance? Andrei
Re: Multiple subtyping with alias this and nested classes
language_fan wrote: Fri, 02 Oct 2009 19:35:55 -0300, Leandro Lucarella thusly wrote: We might have very different taste, but I find that a little... horrible. What do you have against mixins? I think you're trying to use D as C++ :) So basically the diamond problem is again implementable in D, yay? Nah, there's no ambiguity - when in doubt, the primary inherited class is the source of the function. AFAIK, alias this only kicks in on otherwise undefined functions.