September 29, 2020
On 9/29/2020 2:56 AM, Petar Kirov [ZombineDev] wrote:
> I don't have experience with multiple inheritance in Eiffel, but it would be shame that in a language with `static if`, `mixin template`s, `static foreach`, etc. we can't figure out a way to make it work.

The more interesting question is "is it worthwhile to make it work?" No.

Too many paths to implicit conversions (and that's really what MI is) leads to nothing but confusion.

(Besides, if we did, we'd break existing code that uses alias this.)
September 29, 2020
On Tue, Sep 29, 2020 at 05:13:31PM -0700, Walter Bright via Digitalmars-d wrote:
> On 9/29/2020 2:56 AM, Petar Kirov [ZombineDev] wrote:
> > I don't have experience with multiple inheritance in Eiffel, but it would be shame that in a language with `static if`, `mixin template`s, `static foreach`, etc. we can't figure out a way to make it work.

I betcha you could do it as a library. ;-)


> The more interesting question is "is it worthwhile to make it work?" No.
> 
> Too many paths to implicit conversions (and that's really what MI is)
> leads to nothing but confusion.
[...]

Yeah, after many years of loving to sprinkle alias this everywhere, I'm starting to realize that it's not such a good idea after all. It leads to code that looks like it's correct, but actually it does something else. Give it a few more iterations of refactoring, bugfixes, and feature additions, and the code quickly becomes totally opaque and hard to reason about. Or just plain ugly because the data structures have turned into a Frankenstein monster where sometimes it's type A, sometimes it's type B, and you have to insert random shunts everywhere to interconvert between them where implicit conversion didn't happen automatically.

Same thing with C++'s implicit constructions and Koenig lookup. It's clever, it's cool, and super-convenient to use... until you have to debug the code, then all of a sudden you're scratching your head, where on earth is that implicit intermediate type that my argument got silently converted to, and which overload did this call end up in?! Sometimes even the debugger won't help you (the implicit conversion got inlined, so you don't even see the intermediate type, just the wrong result in the target function).  Pretty soon, the code becomes write-only, and maintenance costs (time to debug, time to integrate new features, etc.) skyrocket.


T

-- 
Winners never quit, quitters never win. But those who never quit AND never win are idiots.
September 30, 2020
On Wednesday, 30 September 2020 at 00:28:34 UTC, H. S. Teoh wrote:
> On Tue, Sep 29, 2020 at 05:13:31PM -0700, Walter Bright via Digitalmars-d wrote:
>> On 9/29/2020 2:56 AM, Petar Kirov [ZombineDev] wrote:
>> > I don't have experience with multiple inheritance in Eiffel, but it would be shame that in a language with `static if`, `mixin template`s, `static foreach`, etc. we can't figure out a way to make it work.
>
> I betcha you could do it as a library. ;-)
>
>
>> The more interesting question is "is it worthwhile to make it work?" No.
>> 
>> Too many paths to implicit conversions (and that's really what MI is)
>> leads to nothing but confusion.
> [...]
>
> Yeah, after many years of loving to sprinkle alias this everywhere, I'm starting to realize that it's not such a good idea after all. It leads to code that looks like it's correct, but actually it does something else. Give it a few more iterations of refactoring, bugfixes, and feature additions, and the code quickly becomes totally opaque and hard to reason about. Or just plain ugly because the data structures have turned into a Frankenstein monster where sometimes it's type A, sometimes it's type B, and you have to insert random shunts everywhere to interconvert between them where implicit conversion didn't happen automatically.

Well...at work my team uses C++ multiple inheritance in our main product, which is massively event-oriented and multi-threaded. Not tons of it but where we use it, the alternatives would be more verbose, less readable, slower, more complicated. The couple of cases I have in mind right now involve hierarchies that are orthogonal. There are no diamonds, because they would make no sense at all. So, better code and no headaches. Who could object to this?

There is a pattern that I have observed in my 30+ year career, it's not easy to phrase it, but it goes something like this: when I found MI handy, it was usually for mixing independent technical aspects, not so much "modeling the real world". I think that someone mentioned a Button that is both a Drawable and a Clickable. This is the sort of things I have in mind. And if you don't use MI you quickly get a god class that declares dozens of facets, only a few of which are actually implemented in classes scattered across the inheritance tree (think the Microsoft Foundation Classes with its CObject god class).

I also have had success with CLOS-like mixins: small bits of implementation that could be combined easily (of course this is in cases where the combination does not change at runtime), resorting in C++ virtual inheritance and the dominance rule. And this time, diamonds were at the core of the design. Again MI felt like a handy way of organizing my code on a local scale, rather than some ground shaking, mind-opening big statement about "the world" that would open the path to magically cost-free endlessly reusable code.

September 30, 2020
On Wednesday, 30 September 2020 at 00:13:31 UTC, Walter Bright wrote:
> On 9/29/2020 2:56 AM, Petar Kirov [ZombineDev] wrote:
>> I don't have experience with multiple inheritance in Eiffel, but it would be shame that in a language with `static if`, `mixin template`s, `static foreach`, etc. we can't figure out a way to make it work.
>
> The more interesting question is "is it worthwhile to make it work?" No.

If you want to deprecate/replace alias this, then that is the way to go. Otherwise you find alternatives to implicit conversion. Such as implicit copy constructors that was mention a while back.

-Alex
September 30, 2020
On Tuesday, 29 September 2020 at 23:21:19 UTC, Jean-Louis Leroy wrote:

> Looking at your example, I have the impression that the `addr` "feature" is actually a function. If so, `undefine` in this example is simply the equivalent of tacking a `= 0` after an overridden virtual function in C++ (yes you can inherit an implemented virtual function and make it pure again). But, does this also work on attributes?

One cannot undefine attributes, but can rename it, so the programmer can specify individually whether each attribute should be either shared or separated.

I created a 2nd example on how to handle attributes here:

https://github.com/mingwugmail/dlang_tour/blob/master/eiffel/visitor2/visitor.e

class VISITOR
inherit
	UK_RESIDENT
		rename addr as uk_addr
		       make as uk_make
	end
	US_RESIDENT
		rename addr as us_addr
		       make as us_make
	end
	PERSON
		redefine make select make
	end


The generated C-struct is here:

https://github.com/mingwugmail/dlang_tour/blob/master/eiffel/visitor2/app.h#L513

struct S30{Tid id;T0* _name;T0* _addr;T0* _us_addr;T0* _uk_addr;};


As you can see after 3-branch-dimond multiple inheritance, the `name` is shared (there is only 1 copy); while there are 3 address attributes in VISITOR.


September 30, 2020
On Wednesday, 30 September 2020 at 00:13:31 UTC, Walter Bright wrote:
> On 9/29/2020 2:56 AM, Petar Kirov [ZombineDev] wrote:
>> I don't have experience with multiple inheritance in Eiffel, but it would be shame that in a language with `static if`, `mixin template`s, `static foreach`, etc. we can't figure out a way to make it work.
>
> The more interesting question is "is it worthwhile to make it work?" No.
>
> Too many paths to implicit conversions (and that's really what MI is) leads to nothing but confusion.
>
> (Besides, if we did, we'd break existing code that uses alias this.)

I'm fine, if D just stick with single inheritance, just as Java did.

But the problem here is (as we discussed many times): currently with multiple interface, (multiple) mixin, (multiple) subtyping, multiple inheritance *has* crept into D *already*, and in a broken way.

If we have a *broken* effective multiple inheritance already, why not have a *proper* multiple inheritance instead.

September 29, 2020
On Wed, Sep 30, 2020 at 01:26:09AM +0000, mw via Digitalmars-d wrote: [...]
> I'm fine, if D just stick with single inheritance, just as Java did.
> 
> But the problem here is (as we discussed many times): currently with
> multiple interface, (multiple) mixin, (multiple) subtyping, multiple
> inheritance *has* crept into D *already*, and in a broken way.

How is multiple interface broken?  Java has multiple interfaces. Are you saying that Java is broken?  (I wouldn't disagree, but just want to clarify what exactly you mean.)

Mixins are not the same thing. They are a way to inject code into an aggregate, but are not directly recognized as subtyping in the sense of inheritance (i.e., it doesn't implicitly convert).


> If we have a *broken* effective multiple inheritance already, why not have a *proper* multiple inheritance instead.

This is fallacious.  If we have broken feature X, it does not necessarily follow that we must replace it with a non-broken X. Removing X altogether is also a possible solution.


T

-- 
The problem with the world is that everybody else is stupid.
September 30, 2020
On Wednesday, 30 September 2020 at 00:57:52 UTC, Jean-Louis Leroy wrote:

> There is a pattern that I have observed in my 30+ year career, it's not easy to phrase it, but it goes something like this: when I found MI handy, it was usually for mixing independent technical aspects, not so much "modeling the real world". I think that someone mentioned a Button that is both a Drawable and a Clickable. This is the sort of things I have in mind. And if you don't use MI you quickly get a god class that declares dozens of facets, only a few of which are actually implemented in classes scattered across the inheritance tree (think the Microsoft Foundation Classes with its CObject god class).
>

I read a game development book[1] years ago where the author was pushing this approach quite strongly, saying he had published several games where it was used. He referred to it as "mixin inheritance". As long as you reserve MI for introducing behaviors into classes and constrain derived "is-a" relationships to a single (preferably shallow) line in the hierarchy, you are less likely to run into problems.

[1] https://www.amazon.com/Object-Oriented-Game-Development-Julian-Gold/dp/032117660X


September 30, 2020
On Wednesday, 30 September 2020 at 08:44:26 UTC, Mike Parker wrote:
> On Wednesday, 30 September 2020 at 00:57:52 UTC, Jean-Louis Leroy wrote:
>
> I read a game development book[1] years ago where the author was pushing this approach quite strongly, saying he had published several games where it was used. He referred to it as "mixin inheritance". As long as you reserve MI for introducing behaviors into classes and constrain derived "is-a" relationships to a single (preferably shallow) line in the hierarchy, you are less likely to run into problems.
>
> [1] https://www.amazon.com/Object-Oriented-Game-Development-Julian-Gold/dp/032117660X

Yes this is a well known pattern usually called a mixin class:

https://en.wikipedia.org/wiki/Mixin

It's a valid use case, but can easily be achieved in other ways.
September 30, 2020
On Wednesday, 30 September 2020 at 10:15:57 UTC, Abdulhaq wrote:
> On Wednesday, 30 September 2020 at 08:44:26 UTC, Mike Parker wrote:
>> On Wednesday, 30 September 2020 at 00:57:52 UTC, Jean-Louis Leroy wrote:
>>
>
> Yes this is a well known pattern usually called a mixin class:
>
> https://en.wikipedia.org/wiki/Mixin
>
> It's a valid use case, but can easily be achieved in other ways.

I just realised, the prevalence of a concept can be measured by the shortness of its wikipedia URL :-)

sort of....

Kolmogorov sends his regards