Quick thoughts on multiple inheritance
Feb. 5th, 2017 07:23 pmHas-A pattern:
class MyClass { FooType foo; BarType bar; }
- each MyClass allocates space for a FooType and a BarType.
- foo and bar establish their own namespaces.
Inheritance:
class MyClass extends FooType, BarType { }
- each MyClass allocates space for a FooType and a BarType.
- The namespaces for FooType and BarType are incorporated into the MyClass namespace.
So what's the problem? Something in FooType or BarType might overlap.
General outline of a solution:
- All namespace conflicts must be resolved by the programmer.
Considering specific examples:
1. Both FooType and BarType have a .x property?
- Solution 1: Forced upcasting. All attempts to access MyClass.x must be upcasted to the parent. All parent methods work on their own .x property.
2. Both FooType and BarType have a .fooMethod()?
- Solution 1: Forced upcasting. The compiler should warn if the programmer fails to resolve the conflict, and throw an error if the programmer tries to run MyClass.fooMethod() without overriding it. This can cause problems (see case 4).
3. MyClass has its own .x property?
- Solution 1: Override parent access methods. If the property is interface-compatible with the parent's .x property, the FooType/BarType methods will run on MyClass.x instead of their own .x properties. If the property is not interface-compatible with the parent's .x, the compiler should throw an error and refuse to compile. PROBLEM: FooType and BarType may intend for their .x property to mean different incompatible things or to hold separate pieces of information. Sharing the same piece of data will introduce bugs.
- Solution 2: Do not override parent access methods. Parents continue to operate on their own .x properties.
4. MyClass has its own .fooMethod()? Theoretically, this should override the FooType/BarType methods. However, it introduces a double-call problem.
- Solution 1: Override parent methods. This introduces a double-call problem. If both parents have a method called every second that calls their own fooMethod(), this causes the overridden fooMethod() to be called twice per second instead of once per second.
- Solution 2: Do not override parent methods. Parent calls to fooMethod() will call the parent version of fooMethod().
Conclusions
More thought needs to go into this.
- Multiple inheritance is fine until you have a namespace collision, and then you're in trouble.
- If you have the parent classes share data when both have a .x property, then you have the problems that each might treat .x as a different conceptual thing and that conflicting actions on the same .x may introduce race conditions that do not exist when each class uses its own data.
- If you do not have the parent classes share data, then you have multiple copies of what might be the same conceptual thing, updates to one do not affect the other, and the state of ".x" is unclear.
- If the child class .x overrides the property for both parent classes, then you risk the parent methods modifying the data in ways you did not intend.
- If the child's .foo() overrides the method for both parent classes, then you might get a double-call problem when methods in both parent classes call their overridden .foo() method.
- If the child's .foo() does not override the parent method, then you lose the ability to extend the parent class by having its .foo() method do something different.
- The programmer may want to resolve namespace collisions in a different way for different properties and methods in the same class.