◦ ◦◦◦ TECHNISCHE UNIVERSITAT¨ MUNCHEN¨ ◦◦◦◦ ◦ ◦ ◦◦◦ ◦◦◦◦ ¨ ¨ ◦ ◦◦ FAKULTAT FUR INFORMATIK

Programming Languages

Multiple Inheritance

Dr. Axel Simon and Dr. Michael Petter Winter term 2012

Multiple Inheritance 1 / 29 Outline Inheritance Principles

1 Interface Inheritance 2 Implementation Inheritance 3 Liskov Substition Principle and Shapes

C++ Object Heap Layout

1 Basics 2 Single-Inheritance Excursion: Linearization 3 Virtual Methods 1 Ambiguous common parents 2 Principles of Linearization C++ Multiple Parents Heap Layout 3 Linearization algorithm 1 Multiple-Inheritance 2 Virtual Methods 3 Common Parents

Discussion & Learning Outcomes

Multiple Inheritance 2 / 29 “Wouldn’t it be nice to inherit from several parents?”

Multiple Inheritance Inheritance Principles 3 / 29 Interface vs. Implementation inheritance

The classic motivation for inheritance is implementation inheritance Code reusage Child specializes parents, replacing particular methods with custom ones Parent acts as library of common behaviours Implemented in languages like C++ or Lisp

Code sharing in interface inheritance inverts this relation Behaviour contract Child provides methods, with signatures predetermined by the parent Parent acts as generic code frame with room for customization Implemented in languages like Java or C#

Multiple Inheritance Inheritance Principles 4 / 29 Interface Inheritance

DropDownList refresh()

ActionObserver MyDDL changed() changed()

Multiple Inheritance Inheritance Principles 5 / 29 Implementation inheritance

PowerShovel FrontLoader actuate() actuate()

House actuate()

Bulldozer

Undercarriage moveTo(x,y)

Tracks Wheels moveTo(x,y) moveTo(x,y)

Multiple Inheritance Inheritance Principles 6 / 29 Excursion: LSP and Square-Rect-Problem

The Liskov Substitution Principle Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. class Rectangle{ Rectangle r= void setWidth(intw){ this.w=w;} new Square(2); void setHeight(inth){ this.h=h;} r.setWidth(3); void getWidth(){ returnw;} r.setHeight(4); void getHeight(){ returnh;} assertr.getHeight()* } r.getWidth()==12; class Square extends Rectangle{ ! Behavioural assumptions void setWidth(intw){ this.w=w;h=w;} void setHeight(inth){ this.h=h;w=h;} }

Multiple Inheritance Inheritance Principles 7 / 29 “So how do we lay out objects in heap anyway?”

Multiple Inheritance Standard Object Heap Layout 8 / 29 Object layout classA{ int a; int f(int); }; classB: publicA{ int b; int g(int); }; C classC: publicB{ int a int c; int h(int); int b }; int c ...

C c; c.g(42);

%c= alloca %class.C %1= getelementptr %c, i640, i320 %2= call i32 @_g(%1, i32 42) ; g is statically known

Multiple Inheritance Standard Object Heap Layout Object layout & inheritance 9 / 29 Object layout – virtual methods classA{ int a; virtual int f(int); virtual int g(int); virtual int h(int); }; classB: publicA{ int b; int g(int); }; C classC: publicB{ vptr A::f int c; int h(int); int a B::g }; int b ... C::h int c C c; c.g(42);

%c.vptr= getelementptr %c, i640, i640 ; select vptr-entry %1= load %c.vptr ; dereference vptr %2= getelementptr %1, i641 ; select g()-entry %3= load %2 ; dereference g()-entry %4= call i32 %3(%c, i32 42)

Multiple Inheritance Standard Object Heap Layout Virtual Methods 10 / 29 “So how do we include several parent objects?”

Multiple Inheritance Implementation of Multiple inheritance 11 / 29 Multiple Base Classes classA{ int a; int f(int); }; classB{ int b; int g(int); }; A int a B classC: publicA, publicB{ } int c; int h(int); B int b }; ... C int c C c; c.g(42);

%c= alloca %class.C %1= getelementptr %c, i640, i321 ; select B-offset in C %2= call i32 @_g(%1, i32 42) ; g is statically known

! getelementptr hides the ∆B here!

Multiple Inheritance Implementation of Multiple inheritance Multiple base classes in layout 12 / 29 Ambiguities

classA{ void f(int); }; classB{ void f(int); }; classC: publicA, public B {};

C* pc; pc->f(42); ! Which method is called?

Solution I: Explicit qualification Solution II: Automagical resolution pc->A::f(42); Idea: The introduces a pc->B::f(42); linear order on the nodes of the inheritance graph

Multiple Inheritance Implementation of Multiple inheritance Ambiguities 13 / 29 Linearization

Inheritance Relation H Multiplicity M Defined by ancestors. Defined by the order of multiple ancestors.

Principles

1 An inheritance mechanism (maps Object to sequence of ancestors) must follow the inheritance partial order H 2 The inheritance is a uniform mechanism, and its searches (→ total order) apply identically for all object properties (→fields/methods) 3 In any case the inheritance relation H overrides the multiplicity M 4 When there is no contradiction between multiplicity M and inheritance H, the inheritance search must follow the partial order H ∪ M.

Multiple Inheritance Implementation of Multiple inheritance Linearization 14 / 29 Linearization algorithm candidates Depth-First Search W ABWC

! Principle 1 inheritance is violated B C

A

Breadth-First Search W ABCWD

! Principle 1 inheritance is violated D B C A

Multiple Inheritance Implementation of Multiple inheritance Linearization 15 / 29 Linearization algorithm candidates Reverse Postorder Rightmost DFS W ABFDCEGHW G Linear extension of inheritance relation X D EF H B C A Reverse Postorder Rightmost DFS FG ABCDGEF

! But principle 4 multiplicity is violated! B D E C A

Multiple Inheritance Implementation of Multiple inheritance Linearization 16 / 29 Linearization Algorithm

Idea [Ducournau and Habib(1987)] Successively perform Reverse Postorder Rightmost DFS and refine inheritance graph G with contradiction arcs.

The reservoir set of potential contradiction arcs CA is initially M, while the inheritance graph G starts from H. do

1 search ← RPDFSG 2 CA ← {contradiction arcs of upper search} ∩ M 3 G ← G ∪ CA; while (CA 6= ∅) ∧ (search violates H ∪M)

Multiple Inheritance Implementation of Multiple inheritance Linearization 17 / 29 Linearization vs. explicit qualification

Linearization Qualification No switch/duplexer code More flexible, fine-grained necessary Linearization choices may be No explicit naming of qualifiers awkward or unexpected Unique super reference

Languages with automatic linearization exist CLOS Common Lisp Object System Prerequisite for → Mixins

Multiple Inheritance Implementation of Multiple inheritance Linearization 18 / 29 Virtual Tables for Multiple Inheritance classA{ int a; virtual int f(int); }; classB{ int b; virtual int f(int); virtual int g(int); vptr 0 B A RTTI }; } int a C::f classC: publicA, publicB{ vptr B int c; int f(int); B int b RTTI }; C::Bf ... C int c B::g C c; B* pb=&c; pb->f(42);

%1= getelementptr %c, i640, i321, i640 ;select B-offset in C %2= load i32 %1 ;load vptr-entry %3= load i32 %2 ;load f()-thunk-entry %5= call i32 %3(%1, i32 42)

Multiple Inheritance Implementation of Multiple inheritance Virtual Table 19 / 29 Virtual table

A Virtual Table consists of different parts: 0 1 the constant offset of an objects heap RTTI representation to its parents heap C::f representation B RTTI 2 a pointer to a runtime type information C::Bf object (not relevant for us) B::g 3 method pointers of the overwritten methods for resolving virtual methods

Several virtual tables are joined when multiple inheritance is used Casts! The vptr field in each object points at the beginning of the first virtual method pointer

Multiple Inheritance Implementation of Multiple inheritance Virtual Table 20 / 29 Virtual table 2

Remarks: The virtual table is created at compile time and filled with offsets, virtual method pointers and thunks ∆B is the relative position of the B part in C, and known at compile time. This entry is primarily used for dynamic casts: C c; B*b=&c; void*v= dynamic_cast(b); printf("%d, %d, %d",&c,b,v);

Multiple Inheritance Implementation of Multiple inheritance Virtual Table 21 / 29 Virtual table 3

Remarks: thunks are trampoline methods, delegating the virtual method to its original implementation with an adapted this-reference C c; B*b=&c; b->f(42); /* f(int) provided by C::f(int), addressing its variables relative to C */ B-in-C-virtual table entry for f(int) is the thunk _f(int), adding ∆B to the this parameter define i32 @__f(%this, i32 %i){ %1= getelementptr %this, i64 -1, i320, i320 %2= tail call i32 @_f(%1, i32 %i) ret i32 %2 }

Multiple Inheritance Implementation of Multiple inheritance Virtual Table 22 / 29 “But what if there are common ancestors?”

Multiple Inheritance Implementation of Multiple inheritance Virtual Table 23 / 29 Distinguished base classes classL{ int l; virtual void f(int); }; classA: publicL{ 0 int a; void f(int); RTTI vptr }; A::f L int l classB: publicL{ B B int b; void f(int); } A int a RTTI }; vptr B::f classC: publicA, publicB{ L int l int c; B int b }; ... C int c C c; L* pl=&c; pl->f(42); C* pc=(C*)pl; ! Ambiguity! L* pl=(A*)&c; C* pc=(C*)(A*)pl;

Multiple Inheritance Implementation of Multiple inheritance Distinguished base classes 24 / 29 Common base classes classW{ W int w; virtual void f(int); 0 virtual void g(int); RTTI vptr A::f virtual void h(int); C::h }; A int a W- B classA: public virtualW{ vptr B int a; void f(int); RTTI B int b B::g }; W classB: public virtualW{ C int c RTTI int b; void g(int); A::Wf vptr }; B::Wg W int w classC: publicA, publicB{ C::Wh int c; void h(int); }; ! Offsets to virtual base ... ! Ambiguities C* pc; e.g. overwriting f in A and B pc->f(42); ! Casting! ((W*)pc)->h(42); W* pw=&c; ((A*)pc)->f(42); C* pc=(C*)pw;

Multiple Inheritance Implementation of Multiple inheritance Common base classes 25 / 29 Compiler and Runtime Collaboration

Compile time: 1 Compiler generates one code block for each method per class 2 Compiler generates one virtual table for each class, with

I references to the most recent implementations of methods of a unique common signature

I static offsets of top and virtual bases 3 Each virtual table may be composed from customized virtual tables of parents ( thunks) 4 If needed, compiler generates thunks to adjust the this parameter of methods Runtime: 1 Calls to constructors allocate memory space 2 Constructor stores pointers to virtual table (or fragments) respectively 3 Method calls transparently call methods statically or from virtual tables, unaware of real class identity 4 Dynamic casts may use top pointer

Multiple Inheritance Implementation of Multiple inheritance Compiler and Runtime Collaboration 26 / 29 Polemics of Multiple Inheritance

Full Multiple Inheritance (FMI) Multiple Interface Inheritance (MII) Most powerful inheritance MII not as complex as FMI principle known MII together with aggregation More convenient and simple in expresses most practical the common cases problems Occurance of diamond Killer example for FMI yet to be problem not as frequent as presented discussions indicate Too frequent use of FMI considered as flaw in the class hierarchy design

Multiple Inheritance Discussion 27 / 29 Lessons Learned

Lessons Learned

1 Different purposes of inheritance 2 Heap Layouts of hierarchically constructed objects in C++ 3 Virtual Table layout 4 LLVM IR representation of object access code 5 Linearization as alternative to explicit disambiguation 6 Pitfalls of Multiple Inheritance

Multiple Inheritance Discussion 28 / 29 Further reading...

CodeSourcery, Compaq, EDG, HP, IBM, Intel, Red Hat, and SGI. Itanium C++ ABI. URL: http://www.codesourcery.com/public/cxx-abi.

Roland Ducournau and Michel Habib. On some algorithms for multiple inheritance in object-oriented programming. In Proceedings of the European Conference on Object-Oriented Programming (ECOOP), 1987.

Barbara Liskov. Keynote address – data abstraction and hierarchy. In Addendum to the proceedings on Object-oriented programming systems, languages and applications, OOPSLA ’87, pages 17–34, 1987.

Robert C. Martin. The liskov substitution principle. In C++ Report, 1996.

Bjarne Stroustrup. Multiple inheritance for C++. In Computing Systems, 1999.

Multiple Inheritance Further materials 29 / 29