Lecture 18 Inheritance Dynamic Method Binding Subtyping class Square { int w; int height() = { return w; } int width() = { return w; } int area() = { retrun w * w; } ^^^^^ height() * width() } class Rect extends Square { int h; int height() = { return h; } // if area() was defined as height()*width(), it needs not to be overridden } Subtyping principle: anywhere you expect a certain type, it's ok to give you a subtype of that type. "tension" conflict between inheritance and subtyping. e.g., Rect inherits Square, but Square is a subtype of Rect. Because of the detail layout (namely, extended items are added at the end) for anywhere you expect a square, I give you a Rect, you simply ignore newly added fields you still get same offset to access whatever you'd like to with a Square. Of course, you may get thing that's overridden, but that's the effect you want. This becomes messy when you have multiple inheritance. Subtyping Notation: t =< t' to stand for that t is a subtype of t' Three ways to subtyping: - extension {..., x_i:t_i, ...} U {x_n+1 : t_n+1} =< {..., x_i:t_i,...} open versus closed interpretation ^^^ less specific rather than exclusive - covariant relationship {x_1:t_1, ..., x_n:t_n} =< {x_1:t'_1, ..., x_n:t'_n} iff t_i =< t'_i for all i - Contravariant s -> t =< s' -> t' iff t =< t' and s' =< s ^^^^^^^ a function that takes s' type input and return t' type output This rule applies when you override a method. In practice, if you redefine a method in this way in Java, compiler will consider you mean overloading a method. For example, x : t x : t' t =< t' getx: unit -> int getx: unit -> real setx: int -> unit setx: real -> real note: if you allow assignment (setx), you have to have same type for the field. Another example, array of t =< array of t' iff t =< t'. Note: This is ok if you just read things from the array. However, if you can put things into array, the two have to be the same type, namely, t = t'.