5

I would like to deepen the topic of multiple inheritance using Python and I usually find examples that are too simple. I love art and I imagined the following problem and I want to understand if multiple inheritance would be a good design solution for it.

Let's suppose we have STL files (meshes) of 3D scanned faces of ancient Greek/Roman sculptures. You can download this kind of files from websites like, for instance, SketchFab.

Let's suppose we can subdivide our meshes into three main categories:

  • Complete face, i.e. a face having both eyes and ears, nose, mouth and forehead.
  • "Upper" face, i.e. an incomplete/damaged face having both eyes and ears, the upper part of the nose and forehead, so there is no mouth.
  • "Lower" face, i.e. an incomplete/damaged face having only the mouth and the lower part of the nose, so no eyes, no forehead in this case.

Other categories might exist, for example, Left face or Right face or we can have just an eye. However, for the sake of simplicity, I would like to consider only the three categories listed above.

Now, we want to compute geometrical quantities for each face like, for instance, eye width, nose length, mouth width, etc. So we need to implement a bunch of methods.

Let's take a look at the table below. Again, for the sake of simplicity, I am using generic names for the methods.

enter image description here

Both the CompleteFace and UpperFace objects have method_a and both objects implement method_a in the same way. Maybe method_a could represent the eye width. The same logic applies to method_b and method_c. The LowerFace object does not have these methods.

Similarly, both CompleteFace and UpperFace have method_d that represents the same geometrical quantity, however the two objects implement this method using a different algorithm.

method_h is common to all of the three objects and the method is implemented in same way. For instance, this method allows to compute the area of the mesh by summing the area of the triangles composing the meshes.

method_i and method_j are methods implemented only for the CompleteFace object.

The remaining methods (method_k, method_l, etc.) are implemented in the same way by the CompleteFace and LowerFace objects but are not implemented for the UpperFace object.

The question is: what could it be the best design solution for this problem?

Perhaps, multiple inheritance could be used. We create the UpperFace class and the LowerFace class. Then, we create the CompleteFace class which inherits both the UpperFace and LowerFace classes. So, the CompleteFace class inherits method_a, method_b and method_c and there is no need to modify/override them. While method_d needs to be overridden. Finally, method_i and method_j are added. This seems to be a good solution, however multiple inheritance is usually considered a dangerous tool, because of problems like the diamond problem.

Is multiple inheritance the right choice for this problem or should be avoided in favor of other solutions based, for instance, on composition?

blunova
  • 398

2 Answers2

12

I would heavily recommend against using inheritance, this will sooner or later bring you into such kind of trouble mentioned by gnat in his comment. Instead, the very first thing I would recommend here is to design all the methods in a way they make sense for all types of faces.

This may result in certain methods simply returning zero (for example, the eye width for a face with no eyes could simply be zero). If zero isn't a good fit, use NaN, or return an error value, or throw an exception, whatever fits best.

When you are implementing these methods (and give them better names, not just method_a, method_b, ...), you may find out some of them are operating just on certain subdata, for which it may make sense to introduce certain classes on their own. For the sake of this example, lets assume own classes for Mouth, Eye or Nose to be such candidates. Or maybe it is better to have a class FacePart, or maybe that could be a base class for the former: I don't know what fits best for your case, but you get the idea. Now composition comes in: the Face object will contain certain FaceParts and delegate parts of the calculation to those.

How to design these ideas exactly is nothing I would decide up-front here. Better start implementing the methods and refactor whenever you find commonalities or occasions to extract the code into smaller units.

Doc Brown
  • 218,378
9

Multiple inheritance is a dangerous tool, like a chainsaw is a dangerous tool. When you know what you are doing, you can safely use it.

Your example of calculating metrics from scan of potentially damaged sculptures seems to be tailored to suggest multiple inheritance might be a solution. On the other hand, it does not account for the possibility that a left or right half of a face might be missing. Or just the nose or a single eye only.

For calculating geometric properties from potentially damaged sculptures, I would use just a single class and document for each method that it can also return or signal "cannot compute this property from the input data". No inheritance needed on the interface class(es).