next up previous contents
Next: Examples using flexible types Up: Toward more flexible type Previous: Toward more flexible type

Subtyping of method types in subclasses

Figure 8 shows a well-typed class containing methods ${\it {m}}$ and ${\it {n}}$ where ${\it {m}}$ has type Func(S): T. The body of method ${\it {n}}$ includes a message send of ${\it {m(an\_s)}}$ to the implicit receiver, self. We presume that the body of method ${\it {n}}$ will be well-typed if ${\it {m}}$ has type Func(S): T. Suppose we override ${\it {m}}$ in a subclass so that it has type Func(S'): T'. In general, the only way to be sure that the occurrence of ${\it {m}}$ in the body of ${\it {n}}$ is still compatible is to require that ${\it Func(S'):\ T'} {\rm \ <: \ }
{\it Func(S):\ T}$ (this is, after all, exactly what the subtype relation guarantees).


  
Figure 8: Changing types of methods in subclasses.
\begin{figure*}
\begin{verbatim}
class C
 methods
 function m(s:S): T
 begin ......
 ...hich S',T' will this change be safe?
 ... 
end class;\end{verbatim}\end{figure*}

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 ${\it {m_i}}$ of type ${\it {T_i}}$ for $1 \le i \le n$ can be written either

   ObjectType
      m1: T1;
      ...
      mn: Tn
   end ObjectType
or more compactly as ${\it {ObjectType\{m_i:T_i\}_{1 \le i \le n}}}$. The rule for subtyping object types can be written as

\begin{displaymath}
{\rm{\it {ObjectType\{m_j:T_j'\}}}}_{1 \le j \le m} {\rm \ <...
 ...ach }i \le n,\ {\rm{\it {T_i'}}} {\rm \ <: \ }{\rm{\it {T_i}}}.\end{displaymath}

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.


next up previous contents
Next: Examples using flexible types Up: Toward more flexible type Previous: Toward more flexible type
Kim Bruce
10/28/1998