Objects as records

Instructor's Guide


intro, inheritance, subtypes, polymorphism, types, hiding, self-reference, summary, Q/A, literature
Our interest in the subtype relation is primarily directed towards objects. However, since real objects involve self-reference and possibly recursively defined methods, we will first study the subtyping relation for objects as (simple) records. Our notion of objects as records is based on the views expressed in  [Ca84]. Objects may be regarded as records (where a record is understood as a finite association of values to labels), provided we allow functions to occur as the value of a record field.
  
  
  
slide: The object subtype relation

The basic operation with records is field selection which, when the value of the field accessed is a function, may be applied for method invocation. The typing rule for records follows the construction of the record: the type of a record is simply the record type composed of the types of the record's components. See slide 9-objects. In the previous section we have already characterized the subtyping relation between records. This characterization is repeated in slide 9-ex-objects. The following is meant to justify this characterization. Let us first look at a number of examples that illustrate how the subtype relation fits into the mechanism of derivation by inheritance.

Subtyping -- examples

  type any = { }
  type entity = { age : int }
  type vehicle = { age : int, speed : int }
  type machine = { age : int, fuel : string }
  type car = { age : int, speed : int, fuel : string }
  

Subtyping rules

  
  
  
slide: Examples of object subtyping

Suppose we define the type any as the record type having no fields. In our view of types as constraints, the empty record may be regarded as imposing no constraints. This is in agreement with our formal characterization of subtyping, since according to the record subtyping rule the record type any is a supertype of any other record type. Subtyping in the sense of refinement means adding constraints, that is information that constrains the set of possible elements associated with the type. The record type entity, which assumes a field age, is a subtype of any, adding the information that age is a relevant property for an entity. Following the same line of reasoning, we may regard the types vehicle and machine as subtypes of the type entity. Clearly, we may have derived the respective types by applying inheritance. For example, we may derive vehicle from entity by adding the field speed, and machine from entity by adding the field fuel. Similarly, we may apply multiple inheritance to derive the type car from vehicle and machine, where we assume that the common field age (ultimately inherited from entity) only occurs once. Obviously, the type car is a subtype of both vehicle and machine. Each of the successive types listed above adds information that constrains the possible applicability of the type as a descriptive device. The other way around, however, we may regard each object of a particular (sub)type to be an instance of its supertype simply by ignoring the information that specifically belongs to the subtype. Mathematically, we may explain this as a projection onto the fields of the supertype. Put differently, a subtype allows us to make finer distinctions. For example, from the perspective of the supertype two entities are the same whenever they have identical ages but they may be different when regarded as vehicles (by allowing different speeds).

Conformance

The importance of subtyping for practical software development comes from the conformance requirement (or substitutability property) stating that any instance of a subtype may be used when an instance of a supertype is expected. This property allows the programmer to express the functionality of a program in a maximally abstract way, while simultaneously allowing for the refinement of these abstract types needed to arrive at an acceptable implementation. For objects as records, the refinement relation concerns both attributes and functions (as members of the object record). For attributes, refinement means providing more information. Syntactically, with respect to the (signature) type of the attribute, this means a restriction of its range. In other words, the possible values an attribute may take may only be restricted. Alternatively, the refinement relation may be characterized as restricting the non-determinism contained in the specification of the supertype, by making a more specific choice. For example, if we specify the speed range of a vehicle initially as   
  
   then we may restrict the speed range of a car safely to   
  
   . However, to stay within the regime of subtyping we may not subsequently enlarge this range by defining a subtype racing car with a speed range of 0..400 . Intuitively, subtyping means enforcing determinism, the restriction of possible choices. Our (syntactic) characterization of the subtyping relation between object types does not yet allow for data hiding, generics or self-reference. These issues will be treated in sections existential and self-reference. However, before that, let us look at the characterization of the subtyping relation between object types as defined (for example) for the language Emerald. The characterization given in slide 9-emerald is taken from  [DT88].

Subtyping in Emerald -- S conforms to T

  • S provides at least the operations of T
  • for each operation in T, the corresponding operation in S has the same number of arguments
  • the type of the result of operations of S conform to those of the operations of T
  • the types of arguments of operations of T conform to those of the operations of S

slide: The subtype relation in Emerald

The object subtyping relation in Emerald is characterized in terms of conformance. The rules given above specify when an object type S conforms to an object (super) type T. These rules are in agreement with the subtyping rules given previously, including the contravariance required for the argument types of operations. Taken as a guideline, the rules specify what restrictions to obey (minimally) when specifying a subtype by inheritance. However, as we will discuss in the next section, polymorphism and subtyping is not restricted to object types only. Nor are the restrictions mentioned a sufficient criterion for a semantically safe use of inheritance.