5.3. Subtyping

As promised, here is the other half of inheritance, subtyping. A subtyping clause ('<' followed by type specifiers) indicates that the abstract signatures of all types listed in the subtyping clause are included in the interface of the type being defined. In the example, the subtyping clause is
abstract class $SHIPPING_CRATE < $CRATE is ...

The interface of an abstract type consists of any explicitly specified signatures along with those introduced by the subtyping clause.

Points to note about subtyping:

5.3.1. The Type Graph

We frequently refer to the Sather type graph, which is a graph whose nodes represent Sather types and whose edges represent subtyping relationships between sather types. Subtyping clauses introduce edges into the type graph. There is an edge in the type graph from each type in the subtyping clause to the type being defined. The type graph is acyclic, and may be viewed as a tree with cross edges (the root of the tree is $OB, which is an implicit supertype of all other types).
abstract class $TRANSPORT is ...
abstract class $FAST is ...
abstract class $ROAD_TRANSPORT < $TRANSPORT is ...
abstract class $AIR_TRANSPORT < $TRANSPORT, $FAST is ...
class CAR < $ROAD_TRANSPORT is ...
class DC10 < $AIR_TRANSPORT is ...

Since it is never possible to subtype from a concrete class (a reference, immutable or external class), these classes, CAR and DC10 form the leaf nodes of the type graph.

5.3.2. Dynamic Dispatch and Subtyping

Once we have introduced a typing relationship between a parent and a child class, we can use a variable of the type of the parent class to hold an object with the type of the child. Sather supports dynamic dispatch - when a function is called on a variable of an abstract type, it will be dispatched to the type of the object actually held by the variable. Thus, subtyping provides polymorphism.

An example: Generalizing Employees

To illustrate the use of dispatching, let us consider a system in which variables denote abstract employees which can be either MANAGER or EMPLOYEE objects. Recall the defintions of manager and employee
class EMPLOYEE < $EMPLOYEE is ...
   -- Employee, as defined earlier

class MANAGER < $EMPLOYEE is ...
   -- Manager as defined earlier

For the definition of these classes, see unnamedlink

The above defintions can then be used to write code that deals with any employee, regardless of whether it is a manager or not
   main is
      employees:ARRAY{$EMPLOYEE} := #ARRAY{$EMPLOYEE}(3);
      -- employees is a 3 element array of employees
      i:INT := 0;
      wage:INT := 0;
         until!(i = employees.size);
         emp:$EMPLOYEE := employees[i];
         emp_wage:INT := emp.wage;
         -- emp.wage is a dispatched call on "'age'
         wage := wage + emp_wage;
      #OUT + wage + "\n";

The main program shows that we can create an array that holds either regular employees or managers. We can then perform any action on this array that is applicable to both types of employees. The wage routine is said to be dispatched. At compile time, we don't know which wage routine will be called. At run time, the actual class of the object held by the emp variable is determined and the wage routine in that class is called.