Previous Page TOC Next Page



16. Inheritance

Inheritance can be used to define specialisations of previously defined classes. These specialisations are called subclasses (or "children") of their superclasses (or "parents").

16.1 Defining Subclasses

Classes can be subclasses of at most one other class. The superclass (if any) is listed in the head of the class definition.

BNF:

class-decl   ::=   class identifier [ "<" generics-list ">"] is 
         class-definition
class-definition   ::=   [ identifier ] general-class-decl
      | ...

Example

class Car is Vehicle
   == Defines a car for a traffic simulation.
   ...
end class

A subclass inherits all routines and variables from its parent. All interface routines of the parent are also interface routines of the subclass, and all internals (routines and variables) are available inside the subclass. The creation routine is the only routine that is not inherited by the subclass.

Inherited interface routines cannot be "hidden" (removed from the interface). Inheritance is intended to be used to express real "is-a" relationships. If such a relationship is true, there is no need to hide interface routines of the parent. In all situations where a programmer wants to hide parts of an interface in a child, inheritance should not be used, but a client-server model ("uses" relationship) should be used instead.

16.2 Redefinition

Children may redefine the implementation of an inherited routine. This is done by providing a routine implementation in the child with the keyword redefined in the routine header.

BNF:

routine-decl   ::=   identifier [ "(" parameter-list  ")" ] 
            [ "->" "(" parameter-list   ")"] is
         routine-impl
routine-impl   ::=   [ redefined ] routine-body

| ...

Example:

move (dest: Location) is redefined

== Move the position of this ... do
...
end move

The explicit keyword redefined protects a programmer from accidental reuse of a routine name of the parent. The parameter list in the redefined function must be the same as the one of the original function. Changing of parameter lists (covariance or contravariance) is illegal.

Only the implementation of routines may be redefined. It is not allowed to redefine the parameter or result list of an existing routine.

16.3 Calling Superclass Functions

Sometimes is is desirable to call the original of a function that has been redefined (usually as part of the redefinition of the function). Consider the following example:

Example:

class Person is
   ...
   print is 

== Write this person's details to the screen do
print (name, "\n")
print ("date of birth: ", date, "\n")
end print end class class Student is Person ... print is redefined
== Write this student's details to the screen do
super!print - - write Person details
print ("student number: ", stud_num, "\n")
end print end class

The class Person has an interface routine print that prints out that person's details. The class Student, which inherits from Person, redefines print to print out the details for the student, which include the details for a person. Student's print routine can print the person details by calling the original print routine in its superclass. This is done by preceding the routine call with the keyword super and an exclamation mark (!).

BNF:

procedure-call    ::=   call-chain 
call-chain   ::=   [ super "!" ] unqualified-call { "." unqualified-call  }
unqualified-call    ::=   identifier [ "(" expression-list  ")" ]

This construct is often used to call the superclass's creation routine from a childs creation routine.

Example:

class Student is Person
   ...
   interface
      creation (name: String, dob: Date, sid: Integer) is

== Create student instance do
super!creation (name, dob)
student_num := sid
end creation ... end class

I have often been asked why we use an exclamation mark rather than the usual dot notation in this situation. In other words: why do we write

super!creation

instead of

super.creation

The answer is that, although similar on first glance, these are two very different instructions. The dot notation specifies an object before the dot. The routine call is performed on that other object. The exclamation mark (or "bang notation") specifies the execution of a routine that was defined in another class on this object. The super keyword is a scope specifier, not an object specifier. We regard this distinction as so important that we want the programmer to be aware of the difference. The different syntax is an attempt to emphasise this difference.

16.4 Deferred Routines

Routine implementations can be deferred. Deferred routines are marked with the keyword deferred.

BNF:

routine-decl   ::=   identifier [ "(" parameter-list  ")" ] 
            [ "->" "(" parameter-list   ")"] is
         routine-impl
routine-impl   ::=   deferred routine-spec
      | ...
routine-spec   ::=   routine-comment 
      [ pre condition ]
      [ post condition ]
      end identifier 

Example:

move (dest: Location) is deferred

== Move the position of this ...
pre
dest <> nil end move

If a routine is deferred, the class does not provide an implementation of the routine. Classes that contain one or more deferred routines are called abstract classes. No instances can be created of abstract classes. Children of abstract classes can provide implementations for deferred routines. If they do not provide implementations for all deferred routines, they remain abstract themselves.

Implementations for deferred routines are provided by redefining the routine in the child. See section 16.2 for a description of redefinition.

Previous Page TOC Next Page