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 . The rule for subtyping object types can be written as Notice that this is essentially the same rule that we had for record types. When we add the new construct MyType in the next section, the definition of subtyping for object types will become more complex.
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.