Stop inheriting data fields! DDIFI: a new design pattern that solved the diamond problem of multiple inheritance
The diamond problem solved! Using virtual property to decouple the data dependency of the subclass on the superclass, as a clean and general solution to multiple inheritance
In object-oriented programming, data members within a class are like the wooden legs of a table. With the support of these table legs, various functionalities can be implemented on the tabletop, such as placing a flower vase. However, when multiple inheritance is required (which can be imagined as trying to combine many tables together to create a more complex and advanced table), these rigid table legs become difficult to manage: we may need to keep some legs separate while merging others into a single leg.
The DDIFI design pattern is equivalent to replacing the rigid wooden table legs (i.e., concrete data members) with flexible "rope legs" (virtual fields, or abstract data members) in the table (class), thereby providing a clean and general solution to the diamond problem.
As illustrated in following animation:
Traditionally in class based OOP languages, both the fields and methods from the super-classes are inherited by the sub-classes. However this may cause some serious problems in multiple inheritance, e.g. most notably the diamond problem. In this paper, we propose to stop inheriting data fields as a clean and general solution to such problems.
We first present a design pattern to cleanly achieve multiple inheritance in C++, which can handle class fields of the diamond problem exactly according to the programmers’ intended application semantics. It gives programmers flexibility when dealing with the diamond problem for instance variables: each instance variable can be configured either as one joined copy or as multiple independent copies in the implementation class. The key ideas are:
- decouple data interface from data implementation, by stopping inheriting data fields;
- in the regular methods implementation use virtual property methods instead of direct raw fields; and
- after each semantic branching add (and override) the new semantic assigning property.
Then we show our method is general enough, and also applicable to any OOP languages:
- that natively support multiple inheritance (e.g. C++, Python, OCaml, Lisp, Eiffel, etc.), or
- single inheritance languages that support default interface methods (e.g. Java, C# etc.), or
- single inheritance languages that support mixin, and conditional compilation (e.g.
static if
in D), or traits (e.g. Scala).
As an example, in the diamond inheritance problem of <Person, Student, Faculty, and ResearchAssistant
>,
we want to achieve the ideal application semantics: each ResearchAssistant should only have 3 fields:
- one joined copy of
_name
field, but - two separated different address fields:
- one
_student_addr
("dorm") as Student to takeRest(), and - one
_faculty_addr
("lab") as Faculty to doBenchwork()
- one
DDIFI can achieve this ideal application semantics, which is not possible with C++'s plain MI:
DDIFI design pattern:
or in 3D view:
multiple inheritance, diamond problem, program to (data-)interfaces, virtual property, data interface, data implementation, semantic branching site, reusability, modularity
This work is patent pending, as already stated in the https://github.com/joortcom/DDIFI/blob/main/ddifi.pdf.