Thus we can guarantee type safety when forming subclasses if we
restrict ourselves to overriding a method with a new one whose type is a
subtype of the type of the original.
By a similar analysis of message sending outside of the object's methods, one can easily show that this restriction on changing the types of methods in subclasses is sufficient to guarantee that the resulting object types will be subtypes. Later we will add more flexible constructs to our language that will result in subclasses sometimes failing to generate subtypes. However the implicit mutually recursive definitions of methods will still require us to restrict changes in types of methods to subtypes.
We can write down the subtype relation on object types more formally.
An object type that supports methods of type
for
can be written either
ObjectType m1: T1; ... mn: Tn end ObjectTypeor more compactly as
Because methods are always functions or procedures, we can indicate more exactly the changes allowed to types of methods in subclasses. Recall from the previous section that subtyping of function types is contravariant in the parameter type and covariant in the result type. Thus in overriding a method in a subclass, we may replace a result type by a subtype and a parameter type by a supertype. This flexibility in changing result types is clearly very useful. However few compelling examples seem to exist of the value of replacing a parameter type by a supertype. The most likely scenario for thus changing parameter types is if the original method had parameters that were needlessly narrow and could thus be easily broadened in the method for the subclass.