All of them have the same problem. It just shows up in different ways.
In C++ case you have two main issues:
- the decision to have or not virtual base classes, due to C++ design
of only paying for what you use, the common solution to duplicate data
members in OO languages is explicit in C++
- even if one restricts him/herself to use pure abstract classes without
data members, as a way to implement interfaces, there is the problem of
function members collisions.
Some OO languages with inheritance of state usually get away with the data
member duplication, either by doing what C++ compilers do with virtual base
classes.
The ones that adopt only some form interfaces/traits, have to deal with name
clashes the same way as C++.
All the existing solutions are kind of good enough, but not perfect:
- Using of some form of linearisation algorithm every developer needs to
be aware of, to understand which methods wins;
- Members need to be renamed, thus changing the real interface meaning
- Implementations are provided for each collided method, requiring either casts to specific interfaces or explicit calls for the right method
- Provide just one implementation, with the caveat the semantics might not match all the interfaces that share the same method signature
- Not allowing collisions, forcing the creation of an adapter interface
So it is not well in the MI solutions outside C++. Each approach has plus and minus.
In C++ case you have two main issues:
- the decision to have or not virtual base classes, due to C++ design of only paying for what you use, the common solution to duplicate data members in OO languages is explicit in C++
- even if one restricts him/herself to use pure abstract classes without data members, as a way to implement interfaces, there is the problem of function members collisions.
Some OO languages with inheritance of state usually get away with the data member duplication, either by doing what C++ compilers do with virtual base classes.
The ones that adopt only some form interfaces/traits, have to deal with name clashes the same way as C++.
All the existing solutions are kind of good enough, but not perfect:
- Using of some form of linearisation algorithm every developer needs to be aware of, to understand which methods wins;
- Members need to be renamed, thus changing the real interface meaning
- Implementations are provided for each collided method, requiring either casts to specific interfaces or explicit calls for the right method
- Provide just one implementation, with the caveat the semantics might not match all the interfaces that share the same method signature
- Not allowing collisions, forcing the creation of an adapter interface
So it is not well in the MI solutions outside C++. Each approach has plus and minus.