CSE 505 Lecture Notes:
Inheritance
November 7, 1994
Implementation inheritance, abstract type inheritance, or both?
Here will consider implementation inheritance. Type inheritance, or
subtyping, is discussed in
Types in Object Oriented Languages.
"super" mechanism in Smalltalk (as discussed in the
Smalltalk Notes)
"inner" in Simula and BETA: the method in superclass can have the reserved
word "inner" this calls a method of the same name in a subclass (superclass
in control).
We could do this in Smalltalk with a programming discipline; different
programming philosophy though.
Multiple (implementation) inheritance
is multiple inheritance needed or useful?
- code sharing (pragmatics)
- system modeling (Scandanavian school of object-oriented programming)
Multiple inheritance ambiguities
(1) A (2) A clam
/ \ / \
B clam C B C
\ / \ /
D D
(3) A (4) A clam
/ \ / \
B clam C clam B clam C
\ / \ /
D D
Old Smalltalk multiple inheritance extension (1982)
Conservative approach to conflict resolution: (3) and (4) would both yield
conflicting inheritance errors
Accessing overridden or ambiguous methods:
standard Smalltalk: super clam
extension: self B.clam,
self C.clam
self super.clam
self all.clam
building class name into a selector a mistake -- c.f. SELF
Examples of use:
- Transcript inherits from Window, WriteStream
- ReadWriteStream inherits from ReadStream, WriteStream
- QueueableWindow inherits from Window, Link
- PanedTitledScrollingWindow inherits from ... [mixins!]
Other issues (see paper):
- browser support
- implementation
- instance state
- dynamic updating
CLOS
CLOS has rules for choosing which method to invoke - don't usually
get ambiguities before and after methods, wrappers
numerous other hairy features
using metaobject protocol
Form linear ordering, using these rules:
- A class preceeds its direct superclass
- A direct superclass preceeds all other direct superclasses to its right
in the defclass superclass list
In above example, the ordering would be [D,B,C,A]
Here is some sample code to demonstrate this:
(defclass A () ()) ; class A has no superclasses
(defclass B (A) ()) ; class B is a subclass of A
(defclass C (A) ())
(defclass D (B C) ()) ; class D is a subclass of both B and C
(defmethod clam ((obj A)) (format t "clam method for A~%"))
(defmethod clam ((obj C)) (format t "clam method for D~%"))
;; ***** running the code *****
;;
;; (setq inst (make-instance 'D))
;; (clam inst)
This doesn't resolve every ambiguity -- there is also a ridiculously hairy
rule in the Common Lisp specification to specify the linear ordering
completely. As an example, consider
A
/ \
B C
| |
D E
\ /
F
In this case the ordering is [F,D,B,E,C,A] (in particular, note that B comes
before E).
before primary after
before primary after
before primary after
call-next-method
around
call-next-method
around
call-next-method
around
- various ways of combining results from primary methods, if desired:
- list them, and them, or them, add them, slice them, dice them, ...
Inheritance and Encapsulation
Snyder's classic 1986 OOPSLA paper points out a number of encapsulation
problems with the inheritance scheme in languages like Smalltalk:
- subclasses get direct access to instance variables inherited from a
superclass. Normally one would like to be able to change the
representation used in a class; as long as the external (message) interface
is the same, clients shouldn't need to know about the change. This doesn't
work for subclasses (which Snyder views as kinds of clients).
- there are problems with mixing implementation and abstract type
inheritance (they are not always the same)
- the programmer should be able to declare some methods to be private
- graph-oriented multiple inheritance schemes implicitly make the
inheritance hierarchy above a class part of its interface
- linearization schemes can lead to errors in which one method overrides
another, even though the programmer didn't intend it
Snyder's proposed solutions:
- access to inherited instance variables via messages
(note: in SELF, Cecil, and Kaleidoscope, ALL instance variable access is
handled this way)
- allow operations to be excluded for implementation inheritance
- separate implementation and abstract type inheritance
- tree-oriented multiple inheritance scheme
- C++
- has public, protected, and private attributes
public, private, protected inheritance
"friends"