25
1 Multi-Methods: The Double-Dispatch Multi-Methods: The Double-Dispatch Idiom Idiom abstract class Ball { ... // method, fields for painting/moving a ball static final Color DARK_RED = new Color(150,0,0); static final Color DRAK_GREEN = new Color(0,150,0); abstract Color mix(Ball b); abstract Color mixRed(RedBall b); abstract Color mixGreen(GreenBall b); } class RedBall extends Ball { Color mix(Ball b) { return b.mixRed(this); } Color mixRed(RedBall b) { retrun DARK_RED; } Color mixGreen(GreenBall b) { return Color.YELLOW; } } class GreenBall extends Ball { Color mix(Ball b) { return b.mixGreen(this); } Color mixRed(RedBall b) { return Color.YELLOW; } Color mixGreen(GreenBall b) { return DARK_GREEN; } }

1 Multi-Methods: The Double-Dispatch Idiom abstract class Ball {... // method, fields for painting/moving a ball static final Color DARK_RED = new Color(150,0,0);

  • View
    215

  • Download
    2

Embed Size (px)

Citation preview

1

Multi-Methods: The Double-Dispatch IdiomMulti-Methods: The Double-Dispatch Idiomabstract class Ball { ... // method, fields for painting/moving a ball

static final Color DARK_RED = new Color(150,0,0); static final Color DRAK_GREEN = new Color(0,150,0); abstract Color mix(Ball b); abstract Color mixRed(RedBall b); abstract Color mixGreen(GreenBall b); }class RedBall extends Ball { Color mix(Ball b) { return b.mixRed(this); } Color mixRed(RedBall b) { retrun DARK_RED; } Color mixGreen(GreenBall b) { return Color.YELLOW; }}class GreenBall extends Ball { Color mix(Ball b) { return b.mixGreen(this); } Color mixRed(RedBall b) { return Color.YELLOW; } Color mixGreen(GreenBall b) { return DARK_GREEN; }}

2

ConformanceConformance

Same or Better Principle Access Conformance Contract Conformance Signature Conformance

3

What’s Conformance?What’s Conformance? Overriding: replace method

body in sub-class. Subtyping: subclass is usable

wherever superclass is usable. Dynamic Biding: consequence

of overriding + polymorphism. Select right method body

Conformance: overriding and overridden should be equivalent

f(arg1, arg2){ xxx}

Superclass

f(arg1, arg2){ yyy}

Subclass

pp->f(...)

p->f(...)

yyy should " conform " to xxx

4

Conformance and Class InvariantsConformance and Class Invariants Question:

Let v be the invariant of a class C.

Let v’ be the invariant of a class C’ derived from C.

Then, what should be the relationship between v and v’? Answer:

v’ => v Rationale: a non-overridden method of C assumes v. This

assumption must hold even if the method is applied to an object of class C’.

Example: A Square inheriting from Rectangle. V = Rectanble invariants:

All angles are right angles Opposite sides are parallel and equal

V' = Square invariants = V + All sides are equals

5

Conformance and OverridingConformance and Overriding Ideally, an overriding method should be

“semantically compatible” with the overridden one. All versions of “draw” should draw the object. Not well-defined. Impossible to guarantee!

We must content ourselves with conformance in the following aspects:

Access. Contract: pre- and post-conditions, thrown exceptions. Signature: input arguments, output arguments, input-output

arguments, function result.

6

Conformance and Dynamic TypingConformance and Dynamic Typing In dynamically-typed languages conformance is not an

issue

Conformance is hard only when you try to decide “semantic compatibility” at compile-time

Under dynamic typing a “sematnic incompatibility” is just one of many kinds of run-time errors

7

““Same or better” PrincipleSame or better” Principle

Same or better: An overriding method should have at least the same functionality as the overridden method.

Overriding should not pose surprises to client.

More realistically: All that can be checked is static typing. The “type” of the overriding method should be a super-type of

the “type” of the overridden one.

The overriding method should have the same or more “calling patterns” as the overridden one.

8

Access ConformanceAccess ConformanceAll versions of a method should have the same visibility.

Smalltalk: All methods are public. Java: Subclass can only improve the visibility of a method C++: Not enforced, may lead to breaking of encapsulation.

class X {public:

virtual void f() { ... }};

class Y: public X { private:

void f() { ... }};

Y* y = new Y();

X* x = y;

y->f(); // Error! Y::f is private.x->f(); // OK! (but breaks encapsulation.)

9

Friendship and OverridingFriendship and OverridingA friend of base class is not necessarily a friend of the derived class.

class X { friend void amigo(); virtual void f() { ... }};

class Y : public X { void f() { ... } // Visibility is the same, or is it? };

void amigo() { Y* y = new Y(); y->f(); // Error! Y::f is private. X* x = y; x->f(); // OK! the same method is now visible}

10

Conformance of ContractsConformance of Contracts Rules of contract conformance.

Pre-condition: Overriding method must demand the same or less from its client.

Post-condition: Overriding method must promise the same or more to its client.

In other words: overriding method should be less spoiled!

Rationale: “Same or better principle”

11

Eiffel: Design By ContractEiffel: Design By Contract

class ACCOUNTfeature {NONE} balance: INTEGER count: INTEGERfeature {ANY} deposit(sum:INTEGER) is require non_negative: sum >= 0 do balance := balance + sum; count := count + 1; ensure balance >= 0; count = old count + 1; endend

12

Eiffel: Inheritance of ContractsEiffel: Inheritance of Contracts

Pre and post conditions are inherited.

They can be refined, but never replaced. Pre-condition refinement:

inherited_pre_condition or new_pre_condition Post-condition refinement:

inherited_post_condition and new_post_condition

13

SignaturesSignatures

Elements of signature Input arguments Output arguments Input-Output arguments Return value Exception (in Java)

In C++ exceptions are not part of the signature C++ throws clause is actually a post-condition Checked at run-time

14

Conformance of SignaturesConformance of Signatures Three alternatives

No-variance: The type in signature cannot be changed. Co-variance: Change of type in the signature is in the same

direction as that of the inheritance.

Contra-variance: Change of type in the signature is in the opposite direction as that of the inheritance.

Conformance: Contra-variant input arguments. Co-variant output arguments. No-variant input-output arguments. Co-variant return value. Co-variant thrown exceptions

15

Covariance is Natural & EssentialCovariance is Natural & Essential

DOUBLY L INKED

L IST

S INGLY L INKED

L IST

DOUBLY L INKED

NODE

S INGLY L INKED

NODEinsert()

insert()

More examples: Base: Graph and Node. Derived: MyGraph and MyNode Base: Animal and Food. Derived: Cat and Bones

16

Covariance of Parameters is RiskyCovariance of Parameters is Riskyclass Driver { String name;}

class Trucker extends Driver { int limit;}

class Car { private Driver dr; void setDriver(Driver d) { dr = d; }}

class Truck extends Car { int weight; void setDriver(Trucker t) { if(weight < t.limit) super.setDriver(t); }}

void f() { Driver d = new Driver(); Car c = new Truck(); c.setDriver(d); // Calls Car.setDriver()}

17

Covariance of Return Type is FineCovariance of Return Type is Fine

class Driver { String name; }class Trucker extends Driver { int limit; }

class Car { private final Driver dr; Car(Driver d) { dr = d; } Driver getDriver() { return dr; }}

class Truck extends Car { Truck(Trucker t) { super(t); } Trucker getDriver() { return (Trucker) super.getDriver(); }}

void f() { Truck t = new Truck(new Trucker()); Car c = t; Driver d = c.getDriver(); d = t.getDriver(); Trucker trucker = t.getDriver(); }

18

Variance of Inputs ArgumentsVariance of Inputs Arguments Suppose that:

m is a method of the superclass m takes an argument of type C m is overridden by m’ in a subclass

What is the type of the corresponding argument of m’ in the derived class?

Variance Type

No-variance

Contra-variance

Co-variance

Argument Type

Must be C

C or base class thereof

C or derived class thereof

Programming Language Example

C++, Java

Sather

Eiffel

19

Co-variance and Static TypingCo-variance and Static Typing We have seen that co-variance is type unsafe.

It may generate run-time type errors. Q: How can co-variance exist in Eiffel ?

Remember: Eiffel has static type checking A: Eiffel's type system has “holes”

Some messages will not have a compatible method in the receiver The developer should be aware of that

(Similar to programming in a dynamically typed language) => A subclass with a covariant overriding is not a proper

subtype of its superclass The compiler will allow assignability But, you may get a “method-not-found” runtime error

Possible solution: A whole-world-analysis The compiler tries to find all possible assignments to a variable

=> Tries to predict the dynamic type of all variables Cannot be achieved in the general case

20

Binary MethodsBinary Methods A special case of a method with a covariant argument

The argument is of the same type as the receiver Frequently occurs in many domains: E.g.: Comparison & Sorting, Arithmetics , Recursive Data-

structures (graphs)

class Point { int x, y; boolean same(Point p) { return x == p.x && y == p.y; }}

class ColorPoint extends Point { Color color; boolean same(ColorPoint cp) { return x == cp.x && y == cp.y && color == cp.color; }}

21

Binary Methods (cont.)Binary Methods (cont.) Partial solutions

like current (Eiffel) Recursive genericity (Java) Self type (LOOM)

If used in a contra-variant position, then no subtyping

// Pseudo-code: LOOM class Point { int x, y; boolean same(ThisClass p) { return x == p.x && y == p.y; }}

class ColorPoint extends Point { Color color; boolean same(ThisClass cp) { return x == cp.x && y == cp.y && color == cp.color; }}

Point p = new ColorPoint(); // Error – Not a subtype!

22

Summary: Variance in C++, JavaSummary: Variance in C++, Java As a rule: No Variance!

Exact match in signature required between: Overriding method Overridden method

If a method has a covariant argument... ...It does not override the “old” method Java: The new method overloads the old one In C++: The new method hides the old one

Relaxation: Co-variance is allowed in the return value A later addition to both languages Type safe Quite useful

23

Covariance + Overloading = HeadacheCovariance + Overloading = Headache This is a legal Java program Recall: Covariance of arguments => Overloading

class A { boolean f(A a) { return true; } } class B extends A { boolean f(A a) { return false; } boolean f(B b) { return true; } }

void f() { A a = new A(); A ab = new B(); B b = new B();

a.f(a); a.f(ab); a.f(b); // true, true, true ab.f(a); ab.f(ab); ab.f(b); // false, false, false b.f(a); b.f(ab); b.f(b); // false, false, true}

24

Conformance and # ArgumentsConformance and # Arguments Suppose that:

m is a method of a base class taking n arguments m is overridden by m’ in a derived class.

Then, how many arguments should m’ have? Exactly n:

Most current programming languages. n or less:

It does not matter which arguments are omitted as long as naming is consistent.

n or more: The BETA programming language (daughter of Simula).

Note that adding arguments in an overriding method violates the “same or better” principle!

25

Conformance of FieldsConformance of Fields Usually, fields can be read-from and written-to

Similar to input-output arguments of a method Thus, an overriding field should not change the field's type

(No-variance) But, in most languages there's no overriding of fields...

What about final fields? They can only be read from – just like return values Thus, covariance of final fields is OK