Lecture 22
Multiple Inheritance, Mixins, Interfaces, Abstract Methods
Programming Languages
UW CSE 341 - Winter 2023
What next?
Done: classes for OOP essence: inheritance, overriding, dynamic dispatch
Now: what if we want to have more than just 1 superclass
Multiple Inheritance
Trees, dags, and diamonds
A
B
C
D
E
X
Y
V
W
Z
What could go wrong?
X
Y
V
W
Z
color-point-3d% (??)
This is completely made up (doesn’t work) but shows what we might want
class ColorPoint3D extends Point3D, ColorPoint { … } //no!
; This is NOT Racket
(define color-point-3d%
(class (list color-point% point-3d%) ; multiple superclasses
(super-new color-point%)
(super-new point-3d%) ; wait, does this init point% again?
(inherit-from point-3d% dist-to-origin)
(define/override (->string)
(string-append (send this get-color)
":" (super point-3d% ->string)))))
Artist Cowboys
7
(define person% (class object% (super-new) …
(define/public (get-pocket-contents)))
(define artist% (class person% (super-new) …
(send this set-pocket-contents! (new brush% …))
(define/public (draw) …)))
(define cowboy% (class person% (super-new) …
(send this set-pocket-contents! (new gun% …))
(define/public (draw) …)))
(define artist-cowboy%
(class (list artist% cowboy%) …)) ; This is NOT Racket!
Mixins
Special support?
Various OOP languages have special constructs that enable mixins by one name or another
But do we need special support? Depends what else we have...
What is a mixin?
Rather than define “sets of methods” and then have class definitions “include” them, we can…
… define a mixin to “take in some class and produce a new class that also has some extra methods”
So it’s like a function over classes
Or in Racket it is a plain-old function that takes a class as an argument! :-)
No new features needed
We said before classes are first-class values, so this is just an elegant idiom, where colorizer is just a function and parent% is just its argument
(define (colorizer parent%)
(class parent%
(super-new)
(init [color "black"])
(define current-color color)
(define/public (get-color) current-color)
(define/override (->string)
(string-append (get-color) ":" (super ->string)))))
(define color-point2% (colorizer point%))
(define color-point-3d2% (colorizer point-3d%))
A compelling example
A “killer app” for mixins is providing <, >, ==, !=, >=, <= in terms of a three-way compare provided by the superclass
See Racket function comparable and class time-of-day% for examples in the code
Statically-Typed OOP
Classes as Types
class A {
Object m1(Example e, String s) {…}
Integer m2(A foo, Boolean b, Integer i) {…}
}
Interfaces are (or were) Just Types
interface Example {
void m1(int x, int y);
Object m2(Example x, String y);
}
Implementing Interfaces
class A implements Example {
public void m1(int x, int y) {…}
public Object m2(Example e, String s) {…}
}
class B implements Example {
public void m1(int pizza, int beer) {…}
public Object m2(Example e, String s) {…}
}
Purpose of interfaces
Abstract methods
Let’s now answer these questions:
[Explaining Java’s abstract methods / C++’s pure virtual methods]
Required overriding
Often a class expects all subclasses to override some method(s)
Required overriding
A fine Racket approach:
; do not create instances of abstract-foo%
; because baz is used but not defined
(define abstract-foo%
(class object%
(super-new)
(define/public (bar x)
(+ x (send this baz 37)))))
Static typing
(define abstract-foo%
(class object%
(super-new)
(define/public (baz x) (error …))
(define/public (bar x)
(+ x (send this baz 37)))))
Abstract methods
Java/C#/C++ let superclass give signature (type) of method subclasses should provide
abstract class AbstractFoo {
abstract int baz(int x);
int bar(int x) { return x + this.baz(37); }
}
class ReadyToGo extends AbstractFoo {
int baz(int n) { return n * 2; }
}
Passing code to other code
let bar baz x = x + baz 37
let h x = … bar (fun n -> n*2) 12
abstract class AbstractFoo {
abstract int baz(int x);
int bar(int x) { return x + this.baz(37); }
}
class ReadyToGo extends AbstractFoo {
int baz(int n) { return n * 2; }
}
No interfaces in C++
So: Expect to see interfaces only in statically typed OOP without multiple inheritance