You are on page 1of 15

Dynamic Binding

Object-Oriented Programming 236703 Spring 2008
1

Non-Strict Inheritance
• AKA Inheritance • More Powerful Abstraction Mechanism: a subclass is just like the superclass, except for an explicit list of changes:
– Additional operations. – Additional structure elements. – Operations implemented differently, also called overridden operations.

• Note: there is usually no way to “re-implement” structure elements.

Binding Time
• Binding: linking between messages and methods
– Compile Time – Link Time – Execution Time:
• Program Init • Procedure/function begin • Statement Execution

• Inclusion Polymorphism: The same entity may refer to objects of different classes, each of which has a different implementation of the same method • Inclusion Polymorphism + Overriding = Binding Question
– Static Binding (AKA Early Binding): the compiler uses the type of variables to do the binding at a compile (link) time – Dynamic Binding (AKA Late Binding): the decision is made at run time based on the type of the actual values

Static vs. Dynamic Types
• Consider the call:
Employee* e->print(); e = new Manager(); Employee print+

• What is the type of e?
– Static Type:
Employee * • What can be determined in compile time Manager * • Actual type, as determined in run time

Manager print++

– Dynamic Type:

• Which version of print will be called?
– Based on the static type? or, – Based on the dynamic type?

Dynamic Binding and Static Typing
• Static typing: guarantee that a method exists
– A variable of type T can contain only objects of type T, or of type T', where T' is derived from T. – A message to an object is legal only if its static type recognizes it.

• Dynamic binding: make sure that the right method is selected.
– The method invoked for an object depends on its dynamic type.

• Static typing + Dynamic binding: the right combination of safety and power
– Examples: Eiffel, C++, Java, Object-Pascal, TurboPascal, etc.

C++ Example
struct Base { virtual void f() { ... } void g() { ...} }; struct Derived: Base { virtual void f() { ...} // Override f() of Base void g() { ...} // Override g() of Base void h() { ...} } y; Base *px = &y; px->f(); // The right method px->g(); // The wrong method px->h(); // Compile time error! No guarantee that the method exists

Java Example
public class X { public String toString() { return "X"; } public final int addThree(int n) {return n+3; } public static int mul(int a, int b) {return a*b; } } public class Y extends X { public final String toString() { return "Y" + super.toString(); } { What's the binding of super.toString()?

X x = new X(); x.toString(); x.addThree(5); x.mul(3,9);

Y y = new Y(); y.toString(); y.addThree(5); y.mul(3,9);

X x = new Y(); x.toString(); x.addThree(5); x.mul(3,9);

Downcasting vs. Dynamic Binding
void draw(Shape *p) { if (Circle *q = dynamic_cast<Circle *>p) { // Draw circle ... } else if (Line *q = dynamic_cast<Line *>p) { // Draw line ... } else if (Rectangle *q = dynamic_cast<Rectangle *>p) { // Draw rectangle ... } ... }

RTTI considered harmful:
– Order of classes in the if chains is significant – Module must change whenever new class is added to the hierarchy

Forms of Overriding
• Replacement: The new implementation of an operation replaces the implementation of the operation in the base class.
– The only kind of overriding in earlier versions of Eiffel.

• Refinement: The new implementation of an operation refines the implementation of the operation in the base class. It reuses the code of the overridden method. • Usually:
– Overriding method calls inherited method – Just like using:
• super in Smalltalk, Java • Inherited in Turbo-Pascal 7.0 • Precursor in Eiffel

Kinds of Refinement
• Alpha refinement: the overriding operation calls the overridden operation.
– C++, Smalltalk, Java ...

• Beta refinement: the overridden operation must call the overriding version explicitly.
– Excludes replacement! If the implementation in the superclass does not execute an inner command, then the implementation in the subclass is not executed. – Better guarantee of conformance. – Simula, BETA.

Alpha Refinement and Subobjects
• Recall that each object of a subclass has a subobject of the superclass.
– This subobject may have in turn other sub-subobjects in it.

• Alpha refinement involves a forwarding of the message to the subobject. • Mechanisms for forwarding to subobject:
– Smalltalk and Objective-C: super pseudo-variable refers to largest contained subobject. – Object and Turbo Pascal: Inherited keyword refers to the class in which the overridden method was defined. – Eiffel: Precursor keyword. – C++: Must use scope resolution operator explicitly class CheckedArray: public Array { ... explicit CheckedArray(int len): Array(len) {} ... };

• Advantage: The working of the subclass bears more resemblance with that of the superclass. • Disadvantages:
– The designer of an overriding method must be intimately familiar with the workings of the overridden method. – The inner keyword cannot be overridden.

Beta Refinement

• Pseudo C++ Examples:
struct Window { virtual void draw(void) { ... // Set clipping region inner; ... // Restore clipping region } };

struct Object { virtual bool print(void) { if (inner) return; cout << "an object"; return false; } };

Beta Refinement in Flavors
• before and after daemons:
– Called before and after the overriding method – The more general ones daemons wrap around the more specific ones, with the primary method, in the middle – It is possible, in principle, to define daemons also for daemons!

• Example: FramedWindow subclassOf: Window methods: after draw [self drawFrame] TitledFrameWindow subclassOf: FramedWindow methods: after draw [self drawTitle]

Alpha Refinement a-la Flavors
• Wrappers:
– Just like daemons, but defined in the subclass. – More powerful than super since multiple wrappers will nest appropriately, even if an overriding method down the inheritance hierarchy fails to invoke the overridden method.

• Main drawback:
– Confusing semantics!

Programmer Defined Combination
In Flavors, it is possible to define a method combination facility, using the full generality of Lisp:

Class: Military ... methods: generic totalFuelSupply: fuelType [methodCombination: sum] totalFuelSupply: fuelType [ ... ] Class: Army subclassOf: Military methods: totalFuelSupply: fuelType [ ... ]