1 INTRODUCTIONThis is the sixteenth article in a regular series on object-oriented
type theory for non-specialists. Earlier articles have built up The current article examines the mechanism of inheritance
in more detail, looking at the constraints on what may or may not be
added to a class
during inheritance. Most object-oriented languages have restrictions
on the types of overriding methods, to ensure that the resulting subclass
is still type compatible with the superclass. This requires more precise
rules about the typing of 2 MERGING RECORDS AND RECORD TYPESIn the Theory of Classification,
we model objects as simple records of functions, representing their
methods, and object types as the corresponding
record types, containing the signatures of these methods. This leads
to a model of inheritance based on record union with overriding, denoted
by the operator in which the derived result contains
the union of all the fields of base and extra, but fields
from extra are preferred over any identically-labelled
fields from base in the result [3]. This right-handed preference
of So far, we have always used We think of objects as sets of maplets from labels to functions, and object types as corresponding sets of maplets from labels to function types. It is reasonable to think of the merger of two record types as the set union of their respective sets of maplets, since any fields with identical labels will also have identical types. Merging in the subtyping modelIn the subtyping model [10], we must consider the possibility
that fields of different types may be merged. This is because the record
subtyping rule allows fields to be replaced by subtype fields. In this
case, we cannot use That is, we wish to obtain the subtyping relationship Car <: Vehicle.
According to the record subtyping rule [10], this requires Car to have
at least as many fields as Vehicle (it has one more) and requires any
replacement fields to be subtypes. The field home : The above model could be used in languages like Java and C++, which are based on types and subtyping. However, in these languages, a replacement method is typically expected to have exactly the same type as the method it replaces. In more recent versions of C++, the type of this is allowed to be more specific in the result of a replacement method. The overriding rules of Trellis are closest to the subtyping model, allowing both method argument and result types to change in accordance with the function subtyping rule [10]. Merging in the subclassing modelIn the subclassing model, we merge generators and type generators, rather than objects and object types [3, 4]. A curious thing happens when merging records according to the (F-bounded) parametric model: the parameters are instantiated or replaced before any record combination occurs. This means that references to different parametric types on the left and right hand sides become unified before record combination. As a result, record combination always merges records whose common fields have the same types. The following illustrates a simple type generator example, in which a (somewhat simplified) Integer-class generator is defined by extension from a Number-class generator:
We obtain the
subclass relationship: In fact, it is always the case, in the subclassing model, that self-type
parameters are unified before record combination. Likewise, generic
type parameters may
be unified before combination [5] (see also 5.4 below). So, the simpler union
3 SUBSETS, SUBTYPES AND TYPE INTERSECTIONSThroughout this
series, we have been careful to distinguish the notation for
the subset Concrete versus abstract representationThe fundamental relationship is that types may be modelled as sets. When we assert that an element is of a particular type, this is equivalent (in the model) to asserting that the element is a member of a particular set: From this it follows that a subtype may be modelled as a subset: In the universe of types, we want
to show that if x : S and S <: T, then x
: T also. In the universe of sets, x This is the fundamental relationship, which applies to types defined concretely as sets. When we move to defining types abstractly, in terms of their syntactic signatures, then the relationship is different. A record type with more signatures denotes a subtype of a record type with fewer signatures. For example, if the following record types are defined: then it is clear that S is the larger
record type and contains the signatures of T, which we express as T
Intensional versus extensional definitionThere are grounds
for confusion here: in one model, we say: S
To unify the concrete and abstract views of a type, it is easiest to imagine the extension of the type, that is, the set of values (or objects) populating the type. This is the usual view adopted in type theoretical treatments. In object-oriented programming, we usually characterise a class intensionally, that is, by its properties (type signatures). From this, we have to imagine the extension of the class, that is, the possible set of objects which could populate it. Intersection typesHere, we try to establish the relationship between
intensional (signature-based) types and extensional (value-based) types.
Earlier, we modelled type
extension as the union of type-records: Derived = Base From this, we may reason about the extensions of each type. Instances of the Derived type may also be considered instances of the Base type (and instances of the Extra type), by the subtyping rule of subsumption. So, the extension set of the Base type is larger than that of the Derived type; likewise the extension set of the Extra type is larger than that of the Derived type. Since elements of the Derived extension are also members of the Base and Extra extensions, the membership of the Derived extension is precisely the intersection of the memberships of the Base and Extra extensions. For this reason, the kinds of types created by merging signature-based
types are sometimes known as intersection types. Instead of writing:
Base 4 CONSTRAINING THE INHERITANCE FUNCTIONMany object-oriented languages have strict rules about method overriding, during inheritance, because they wish to preserve type compatibility (either subtyping, or subclassing) in the derived type. In C++ or Java, any replacement method must have exactly the same type as the original method it replaces. This imposes a constraint on the inheritance function, which we should like to capture in the model. We shall try to capture this constraint in a general enough way that it will apply both to the first-order subtyping model of inheritance, as found in Java, and also in the second-order subclassing model of inheritance, which is a more appropriate general model for object-oriented programming, in which polymorphic classes and simple types are actually distinct notions. The extend inheritance functionInheritance is only well-defined if
the Extra record provides fields whose types “merge” with
the types of the Base record. This “merge” condition
is expressed as a constraint This definition says that: “extend takes two
type arguments, Base and Extra, where Extra must
satisfy the type-merge condition with Base, then two record
arguments, base : Base and extra : Extra,
and constructs a result by merging the two records, which has the
intersection type (Base Readers will note that the body of extend is identical
to the body of This creates a simply-typed version of
The M type-merge conditionThe all-important type-merge condition This says: “For
all types Base and Extra, the type-merger condition Extra For this, we must assume that the notion of “type equality” is well-defined. In full, this might be expressed by a whole set of rules. For the model of inheritance used in the Theory of Classification, we require the following kinds of type equality: where t is a simple type, Constrained typed inheritanceThe result of extend is well-defined
if Extra and the common
labels in dom(Base) By deliberate design, the same type-merger rule allows the kind of unions of type-records we require for the merger of parameterised record types, which are used in the subclassing model of inheritance. Repeating the example from section 2.2: The Base and
Extra records have the following types, after the parameter substitution
{ and the common labels in
dom(Base) 5 VARIATIONS ON TYPED INHERITANCEThe standard “reference” model
of inheritance consists of the extend inheritance function
and the
Inheritance in SmalltalkSmalltalk is not strongly typed. However, certain rules are still observed about inheritance. A method can only override another method if its untyped “signature” is structurally similar, for example, the method at:put: always has the structural form: Any method in a descendant class must have the
same name and structural form in order to override this method. So,
the “arity” of method arguments
and results is always preserved, although nothing can be said about
the individual types of each argument or result. Smalltalk can distinguish
product types Inheritance in Trellis The type-merger condition above is too restricting to describe
inheritance in Trellis. Trellis allows full subtyping in its overriding
rules,
that is, methods
may be replaced by other methods whose arguments have more general
types and whose results have more specific types, according to the
contravariant
and
covariant parts of the function subtyping rule. To handle Trellis,
we should modify our
definition of This
now allows field types in the Extra record to be subtypes
of common fields in the Base record. The resulting intersection
type
Base requires
the nested intersection: Location Inheritance in Java and C++The original type-merger condition describes exactly the constraint on inheritance in Java, in which all replacement methods must have exactly the same types as the methods they replace. This strict equality nearly describes the condition in C++, apart from the relaxation that applies to returned self-types. We can express this relaxation as: saying
that replacement methods must have the identical types unless they
return the self-type, in which case methods of the function
type: C++ may also have type parameters in its method signatures, if the template class mechanism is used (and so will Java, from version 1.5 onward). The notion of type equality must therefore allow for the comparison both of exact types and type parameters (see 4.2). Inheritance in EiffelThe overriding rules of Eiffel allow methods to be replaced by methods whose arguments and results are both uniformly specialised. This is not legal within a simple subtyping regime; but Eiffel is not based on the subtyping model of inheritance. Elsewhere, Eiffel implicitly evolves the self-type (the type of current) under inheritance and anchors other types to the self-type, especially in binary methods1 such as the infix “+” method in the Numeric class: Because of this, it is tempting to think of Eiffel as following
the F-bounded subclassing model of inheritance, in which “like
current” is actually
a parametric type which are exactly the
same notion as F-bounds. Think of the constrained type parameter
T as a parametric type: This being the case, the reference definition of type-merge is adequate to capture Eiffel’s model of inheritance. You simply have to imagine that all Eiffel class-types are in fact parametric types, which are only fixed when object instances are created. The model of inheritance unifies all the type parameters before combining the records. We illustrate this with a parametric version of the example from 2.1 above: The subclass generator
GenCar reintroduces all the parametric types used within
the class, and substitutes these new parameters inside
the body
of the parent
generator, through the application: GenVehicle[ 6 CONCLUSIONIn this article, we have revisited the notion of
typed inheritance. The Theory of Classification describes
two models of inheritance,
one a first-order
model based on subtyping (Java, C++) and the other a second-order
model based
on
subclassing (Smalltalk, Eiffel). Objects are modelled as records,
or maps from labels to
methods, so inheritance may be modelled as map union with override.
Previously, the classical function override operator We showed how, in the reference model, the constraint merely has to ensure that replacement fields have the same types as the fields they replace. This works for Java-style inheritance (first order) and also for Eiffel-style inheritance (second-order) in which field types may be parametric as well as simply-typed. Variations on this allow replacement fields to be subtypes (Trellis), or a mixture of type-equal and subtype fields (C++). One observation emerging from this is that the ability to replace fields with subtype fields is not a frequent requirement in object-oriented languages. The subclassing model of inheritance only requires type-equality, because all the field types are unified prior to combination, whether by parameter unification [3], or instantiation [5]. Simons and Bruce were the first to note the poor match between simple subtyping and natural models of inheritance [13, 14]. This is what originally motivated the Theory of Classification. Footnotes 1 A binary method is one which accepts an argument of the same type as self. It is binary in the sense that it deals with two objects of the same type.
REFERENCES[1] A J H Simons, “The theory of classification, part 3: Object encodings and recursion”, in Journal of Object Technology, vol. 1, no. 4, September-October 2002, pp. 49-57. http://www.jot.fm/issues/issue_2002_09/column4 [2] A J H Simons, “The theory of classification, part 7: A class is a type family”, in Journal of Object Technology, vol. 2, no. 3, May-June 2003, pp. 13-22. http://www.jot.fm/issues/issue_2003_05/column2 [3] A J H Simons, “The theory of classification, part 8: Classification and inheritance”, in Journal of Object Technology, vol. 2, no. 4, July-August 2003, pp. 55-64. http://www.jot.fm/issues/issue_2003_07/column4 [4] A J H Simons, “The theory of classification, part 9: Inheritance and self-reference”, in Journal of Object Technology, vol. 2, no. 6, November-December 2003, pp. 25-34. http://www.jot.fm/issues/issue_2003_11/column2 [5] A J H Simons, “The theory of classification, part 13: Template classes and genericity”, in Journal of Object Technology, vol. 3, no. 7, July-August 2004, pp. 15-25. http://www.jot.fm/issues/issue_2004_07/column2 [6] A J H Simons, “The theory of classification, part 11: Adding class types to object implementations”, in Journal of Object Technology, vol. 3, no. 3, March-April 2004, pp. 7-19. http://www.jot.fm/issues/issue_2004_03/column1 [7] A J H Simons, “The theory of classification, part 10: Method combination and super-reference”, in Journal of Object Technology, vol. 3, no. 1, January-February 2004, pp. 43-53. http://www.jot.fm/issues/issue_2004_01/column4 [8] A J H Simons, “The theory of classification, Part 15: Mixins and the superclass interface”, in Journal of Object Technology, vol. 3, no. 10, November-December 2004, pp. 7-18. http://www.jot.fm/issues/issue_2004_11/column1 [9] A Compagnoni and B Pierce, “Multiple inheritance via intersection types”, Technical Report ECS-LFCS-93-275, University of Edinburgh, (Edinburgh: LFCS, 1993). [10] A J H Simons, “The theory of classification, part 4: Object types and subtyping”, in Journal of Object Technology, vol. 1, no. 5, November-December, 2002, pp. 27-35. http://www.jot.fm/issues/issue_2002_11/column2 [11]
A Compagnoni, “Subtyping in [12] A J H Simons, “Rationalising Eiffel’s type system”, Proc. 18th Conf. Tech. Object-Oriented Lang. and Sys., eds. R Duke, C Mingins and B Meyer, (Melbourne : Prentice Hall, 1995), 365-377. [13] A J H Simons, “A language with class: The theory of classification exemplified in an object-oriented language”, PhD Thesis, University of Sheffield (Sheffield, Department of Computer Science, 1995). [14] K B Bruce, A Fiech and L Petersen, “Subtyping is not a good “match” for object-oriented languages”, Proc. European Conf. Obj-Oriented Prog. 1997, pub. LNCS 1241, (Jyväskylä: Springer Verlag, 1997) 104-127.
About the author
Cite this column as follows: Anthony J.H. Simons: “The Theory of Classification, Part 16: Rules of Extension and the Typing of Inheritance”, in Journal of Object Technology, vol. 4, no. 1, January-February 2005, pp. 13-25. http://www.jot.fm/issues/issue_2005_01/column2 |