inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with...

30
Inheritance-based subtyping Kathleen Fisher AT&T Labs, Research [email protected] John Reppy Bell Labs, Lucent Technologies [email protected] April 21, 2000 Abstract Classes play a dual rˆ ole in mainstream statically-typed object-oriented languages, serving as both object generators and object types. In such languages, inheritance implies subtyping. In con- trast, the theoretical language community has viewed this linkage as a mistake and has focused on subtyping relationships determined by the structure of object types, without regard to their un- derlying implementations. In this paper, we explore why inheritance-based subtyping relations are useful and we describe two different approaches to extending the MOBY programming language with inheritance-based subtyping relations. In addition, we present a typed object calculus that sup- ports both structural and inheritance-based subtyping, and which provides a formal accounting of our extensions to MOBY. 1 Introduction There is a great divide between the formal study of object-oriented languages and the practice of main- stream languages like JAVA[AG98] and C ++ [Str97]. One of the most striking examples of this divide is the rˆ ole that class inheritance plays in defining subtyping relations. In most foundational descriptions of object-oriented languages, and in the language designs that these studies have informed, inheritance does not define any subtyping relation, whereas in languages like JAVA and C ++ , inheritance defines a subtyping hierarchy. 1 What is interesting about the distinction between inheritance-based and structural subtyping is that there are certain idioms, such as friend functions, binary methods, and object cloning operations, which are natural to write in an inheritance-based framework, but are difficult to express in a structural framework. In this paper, we explore how inheritance-based subtyping relations are useful by examining the common object-oriented idiom of friend functions. Through a series of examples in Section 2, we investigate how one might implement this idiom in MOBY [FR99a], a language with only structural subtyping. We selected friend functions for our case study because they are the canon- ical example of a class permitting outside code to access its internal representation, which is the fort´ e 1 It is important not to confuse inheritance-based subtyping with by-name subtyping. With by-name subtyping, relationships between object types are declared explicitly (e.g.,JAVA’s interfaces). While both inheritance-based and by-name subtyping avoid the accidental subtyping problem that afflicts structural subtyping (the common example of which is a cowboy and widget that both have draw methods), the type names in an inheritance-based scheme are tied to specific implementations, whereas multiple, unrelated classes may be declared to implement the same type name in a by-name scheme. 1

Upload: others

Post on 20-Aug-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

Inheritance-based subtyping

Kathleen FisherAT&T Labs, Research

[email protected]

John ReppyBell Labs, Lucent [email protected]

April 21, 2000

Abstract

Classes play a dual role in mainstream statically-typed object-oriented languages, serving asboth object generators and object types. In such languages, inheritance implies subtyping. In con-trast, the theoretical language community has viewed this linkage as a mistake and has focusedon subtyping relationships determined by the structure of object types, without regard to their un-derlying implementations. In this paper, we explore why inheritance-based subtyping relations areuseful and we describe two different approaches to extending the MOBY programming languagewith inheritance-based subtyping relations. In addition, we present a typed object calculus that sup-ports both structural and inheritance-based subtyping, and which provides a formal accounting ofour extensions to MOBY.

1 Introduction

There is a great divide between the formal study of object-oriented languages and the practice of main-stream languages like JAVA [AG98] and C++[Str97]. One of the most striking examples of this divide isthe role that class inheritance plays in defining subtypingrelations. In most foundational descriptionsof object-oriented languages, and in the language designs that these studies have informed, inheritancedoes not define any subtyping relation, whereas in languageslike JAVA and C++, inheritance defines asubtyping hierarchy.1 What is interesting about the distinction between inheritance-based and structuralsubtyping is that there are certain idioms, such as friend functions, binary methods, and object cloningoperations, which are natural to write in an inheritance-based framework, but are difficult to express ina structural framework. In this paper, we explore how inheritance-based subtyping relations are usefulby examining the common object-oriented idiom offriend functions. Through a series of examplesin Section 2, we investigate how one might implement this idiom in MOBY [FR99a], a language withonly structural subtyping. We selected friend functions for our case study because they are the canon-ical example of a class permitting outside code to access itsinternal representation, which is the forte

1It is important not to confuse inheritance-based subtypingwith by-namesubtyping. Withby-namesubtyping, relationshipsbetween object types are declared explicitly (e.g., JAVA ’s interfaces). While both inheritance-based and by-name subtypingavoid theaccidental subtypingproblem that afflicts structural subtyping (the common example of which is a cowboy andwidget that both have draw methods), the type names in an inheritance-based scheme are tied to specific implementations,whereas multiple, unrelated classes may be declared to implement the same type name in a by-name scheme.

1

Page 2: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

of inheritance-based subtyping. This example illustratesa deficiency of relying solely on structuralsubtyping in object-oriented language design.

We describe how to extend the MOBY programming language with inheritance-based subtyping byaddingclass types. In discussing this extension, we often treat class names asobject types that relatevia inheritance-based subtyping. Class types are a form of object type that are in a one-to-one corre-spondence with the class hierarchy. If an object has a given class type, then that object was instantiatedfrom the associated class or one of its descendants. One class type can be a subtype of a second only ifthe class associated with the first inherits from the class associated with the second,i.e., inheritance is anecessary condition for inheritance-based subtyping. Inheritance need not be a sufficient condition forinheritance-based subtyping, however. In other words, twoclasses may be related via inheritance, buttheir associated class types need not be related via subtyping.

In designing Extended MOBY, we discovered two design alternatives that differ on precisely thisquestion: when should a subclass be considered a subtype of its superclass? In the first alternative, asubclass is a subtype of its parent precisely when the interface of the subclass is a structural subtypeof the interface of its parent. In the second, a subclass is always a subtype of its parent. The firstalternative leads to a simpler type system, while the secondis more expressive. Aside from this onedistinction, the two alternatives are quite similar. Hencewe use the name Extended MOBY to refer toeither extension, using more precise terminology only whennecessary to highlight a difference betweenthe two alternatives. We explore these alternatives in Sections 3 and 4, respectively.

To validate the design of Extended MOBY, we designed a formal object calculus called XMOCwhich models the type system of Extended MOBY. Specifically, XMOC supports both structural andinheritance-based subtyping, as well as a privacy mechanism that allows the interface of a derivingclass to be smaller than the interface of its parent. We present XMOC in Section 5 and sketch a typesoundness proof for it. A more detailed proof appears in Appendix D.

In Section 6 we describe how the type system of Extended MOBY relates to the inheritance-basedsubtyping of C++ and JAVA . Finally, we conclude in Section 7.

2 The problem with friends

Both C++ and JAVA have mechanisms that allow some classes and functions to have greater access priv-ileges to a class’s members than others. In C++, a class grants this access by declaring that certain otherclasses and functions arefriends. In JAVA , members that are not annotated aspublic, protected,or private are visible to other classes in the same package, but not to those outside the package.In this section, we examine how to support this idiom in MOBY, which has only structural subtyping.This study demonstrates that while it is possible to encode the friends idiom in a language with onlystructural subtyping, the resulting encoding is not very appealing.

MOBY is a language that combines an ML-style module system with classes and objects [FR99a].Object types are related by structural subtyping, which is extended to other types in the standard way.One of MOBY’s most important features is that it provides flexible control over class-member visibilityusing a combination of the class and module mechanisms. The class mechanism provides a visibilitydistinction between clients that use the class to create objects and clients that use the class to derivesubclasses, while the module mechanism provides hiding of class members via signature matching. The

2

Page 3: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

module BagM : {type Rep <: Bagobjtype Bag { meth add : Int -> Unit }val union : (Rep, Rep) -> Unitval mkBag : Unit -> Rep

} {class Bag {

public field items : var List(Int)public meth add (x : Int) -> Unit {self.items := x :: self.items

}public maker mk () { field items = Nil }

}objtype Rep = typeof(Bag)objtype Bag { meth add : Int -> Unit }fun union (s1 : Rep, s2 : Rep) -> Unit {

List.app s1.add s2.items}fun mkBag () -> Rep = new mk()

}

Figure 1: Bags and friends using type abstraction

names of class members that are hidden by signature matchingare truly private and can be redefined ina subclass. A brief introduction to MOBY is given in Appendix A.

2.1 Friends via partial type abstraction

A standard way to program friends is to use partially abstract types [PT93, KLM94]. For example,Figure 1 gives the MOBY code for an implementation of aBag class that has aunion function as afriend. In this example, we have ascribed theBagM module with a signature that makes theRep typepartially abstract to the module’s clients. Outside the module, if we have an object of typeRep, wecan use both theunion function and theadd method (sinceRep is a subtype ofBag), but we cannotaccess theitems field. Inside the module, theRep type allows access to all of the members of theBagclass;2 the implementation of theunion function exploits this access. Note that theitems field ispublic inside theBagMmodule, but is not part ofBagM’s interface outside the module. Thus, objectscreated from subclasses ofBag are not known to be structural subtypes ofRep.

Unfortunately, this approach only works forfinal classes. If we want to extend theBag class, wemust reveal the class in the signature of theBagM module (as is done in Figure 2). In this version, anobject created using themkmaker cannot be used as an argument to theunion function. This limitationalso applies to objects created from subclasses ofBag.

2The MOBY notationtypeof(C) is shorthand for the object type that consists of the public members of classC.

3

Page 4: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

module BagM : {type Rep <: typeof(Bag)class Bag {

public meth add : Int -> Unitpublic maker mk of Unit

}val union : (Rep, Rep) -> Unitval mkBag : Unit -> Rep

} {...

}

Figure 2: Revealing theBag class

2.2 Friends via representation methods

To support friends and class extension in the same class requires a public mechanism for mapping froman object to its abstract representation type. With this mechanism, we can recover the representationtype required by the friend functions. For example, supposewe extend ourBag class to include amethod that returns the number of items in the bag. We call this new classCBag (for counting bag),and we want to use theunion function on objects created from theCBag class. Figure 3 presents thisnew implementation. Notice that we have added a public method bagRep to the interface of theBagclass, which returnsself at the representation type (Rep). To apply theunion function to two bagsb1 andb2, we write “Bag.union (b1.bagRep(), b2.bagRep()).” This expression workseven whenb1 and/orb2 are counting bags.

Although this example does not include friends for theCBag class, we have included the represen-tation method in its interface to illustrate the main weakness of this approach. Namely, for each level inthe class hierarchy, we must add representation types and methods. These methods pollute the methodnamespace and, in effect, partially encode the class hierarchy in the object types. Furthermore, thisapproach suffers from the source-code version of thefragile base-classproblem: if we refactor the classhierarchy to add a new intermediate class, we have to add a newrepresentation method, which changesthe types of the objects created below that point in the hierarchy. While this encoding approach appearsto be adequate for most of the examples that require a strong connection between the implementationand interfaces, it is awkward and unpleasant.

3 Extended MOBY

In the previous section, we showed how one can use abstract representation types and representationmethods to tie object types to specific classes. From the programmer’s perspective, a more natural ap-proach is to make the classes themselves serve the role of types when this connection is needed. In thissection and the next, we describe an extension to MOBY [FR99a] that has class types and inheritance-based subtyping. We describe two alternative approaches totyping this extension. These alternativesare distinguished by when they allow a subclass to be viewed as a subtype of its parent class. In thefirst design, a classC is viewed as a subtype of its parent classB only whentypeof(C) is a sub-type oftypeof(B). Because MOBY allows the subclassC to hide (or make private) inherited public

4

Page 5: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

module BagM : {type Rep <: typeof(Bag)class Bag : {

public meth add : Int -> Unitpublic meth bagRep : Unit -> Reppublic maker mkBag of Unit

}val union : (Rep, Rep) -> Unit

} {class Bag {

public field items : var List(Int)public meth add (x : Int) -> Unit {self.items := x :: self.items

}public meth bagRep () -> Rep { self }public maker mkBag () { field items = Nil }

}objtype Rep = typeof(Bag)fun union (s1 : Rep, s2 : Rep) -> Unit {

List.app s1.add s2.items}

}

module CBagM : {type Rep <: typeof(CBag)class CBag : {

public meth add : Int -> Unitpublic meth bagRep : Unit -> BagM.Reppublic meth size : Unit -> Intpublic meth cbagRep : Unit -> Reppublic maker mkCBag of Unit

}} {

class CBag {inherits BagM.Bagpublic field nItems : var Intpublic meth add (x : Int) -> Unit {self.nItems := self.nItems+1;super.add(x)

}public meth size () -> Int { self.nItems }public meth cbagRep () -> Rep { self }public maker mkCBag () { super mkBag(); field nItems = 0 }

}objtype Rep = typeof(CBag)

}

Figure 3: Bags and friends using representation methods

5

Page 6: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

members, the corresponding object types may not be in the subtyping relation (ortypeof(B) mighteven be a subtype oftypeof(C)). In our second design,C may be viewed as a subtype ofB evenwhentypeof(C) is not a subtype oftypeof(B). In both designs, it is possible to hide inheritancerelationships so that they do not induce subtyping relationships.

Although it is not our main motivation, it is worth noting that method and field selection from anobject with a class type can be implemented as a constant timeoperation without sophisticated compileranalysis. When the dispatched method is final in the class type, the compiler can eliminate the dispatchaltogether and call the method directly. In contrast, when an object has an object type, the compilerknows nothing about the layout of the object, making access more expensive.

3.1 Adding inheritance-based subtyping

Our first approach to adding inheritance-based subtyping requires the following additions and modifi-cations to MOBY’s type system.

1. For any classC, we define#C to be itsclass type, which can be used as a type in any context thatis in C’s scope. Note that the meaning of a class type depends on its context. Inside a methodbody, the class type of the host class allows access to all members, whereas outside the class, onlythe public members can be accessed.

2. We extend class interfaces to allow an optionalinheritsclause. If, in a given context, a classC has an interface that includes an “inheritsB” clause, then we view#C as a subtype of#B.Omitting theinheritsclause fromC’s interface causes the relationship betweenB andC to behidden.

3. When a class interface declares that it inherits from a classB, we require that the object typedefined by the public members of the interface be a subtype oftypeof(B).

4. We say that#C is a subtype oftypeof(C). This relation corresponds to Fisher’s observationthat implementation types are subtypes of interface types [Fis96].

5. The existing typing judgements for method and field selection require the argument to have anobject type that includes the given method or field. We modifythese rules to require that theargument be a subtype of an object type that includes the given method or field. Thus when theargument type is a class type, Clause 4 allows the selection to be typed.

6. When typing the methods of a classC, we giveself the type#C (likewise, ifB is C’s superclass,thensuperhas the type#B).

7. When typing anew expression, we assign the corresponding class type to the result.

3.2 Friends revisited

We can now revisit our bag class example using the inheritance-based subtyping features of ExtendedMOBY. In this new implementation (see Figure 4), we use the class type #Bag instead of theReptype, which allows us to simplify the code by both eliminating theRep type and the representation

6

Page 7: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

module BagM : {class Bag : {

public meth add : Int -> Unitpublic maker mkBag of Unit

}val union : (#Bag, #Bag) -> Unit

} {class Bag {

public field items : var List(Int)public meth add (x : Int) -> Unit {self.items := x :: self.items

}public maker mkBag () { field items = Nil }

}fun union (s1 : #Bag, s2 : #Bag) -> Unit {List.app s1.add s2.items

}}

module CBagM : {class CBag : {

inherits BagM.Bagpublic meth size : Unit -> Intpublic maker mkCBag of Unit

}} {

class CBag {inherits BagM.Bagpublic field nItems : var Intpublic meth add (x : Int) -> Unit {self.nItems := self.nItems+1;super.add(x)

}public meth size () -> Int { self.nItems }public maker mkCBag () { super mkBag(); field nItems = 0 }

}}

Figure 4: Bags with friends in Extended MOBY

method. Note that the interface for theCBag class includes aninheritsclause that specifies that it isa subclass ofBag. This relation allows theunion function to be used on values that have the#CBagtype.

3.3 Binary methods

Binary methods are methods that take another object of the same class as an argument [BCC+96].There are a number of different flavors of binary methods, depending on how objects from subclassesare treated. Using class types, we can implement binary methods that require access to the privatefields of their argument objects. For example, Figure 5 showshow theunion function in the previousexample can be implemented as a binary method.

7

Page 8: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

class Bag {field items : var List(Int)public meth add (x : Int) -> Unit {self.items := x :: self.items

}public meth union (s : #Bag) -> Unit {List.app self.add s.items

}public maker mkBag () { field items = Nil }

}

Figure 5: Bags with a binaryunion method.

class B : {public meth getX : Unit -> Intpublic meth clone : Unit -> #Bpublic maker mkB of Intmaker copyB of #B

} {public meth getX () -> Int { self.pvtX }public meth clone () -> #B { new copyB(self) }public maker mkB (x : Int) { field pvtX = x }

public field pvtX : Intmaker copyB (orig : #B) { field pvtX = orig.pvtX }

}

class C {inherits Bpublic meth clone () -> #C { new copyC(self) }public maker mkC (a : Int, b : Int) {

super mkB(a);field y = b

}maker copyC (orig : #C) {super copyB(orig)field y = self.y

}

field y : Int}

Figure 6: Cloning with privacy in Extended MOBY

3.4 Object cloning

Another case where inheritance-based subtyping is useful is in the typing ofcopy constructors. Copyconstructors are useful for implementing object cloning. For example, Figure 6 gives a small ExtendedMOBY class hierarchy that supports object cloning.3 Each class in the hierarchy supports aclone

3This example uses aclass interfaceannotation on the classB; this syntactic form avoids the need to wrapB in a moduleand signature to hide thepvtX field.

8

Page 9: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

typeof(Biface)typeof(Bbody)� <:

#Biface

:>?typeof(C):> -

#Bbody

:>?� = -#C

:>?:> -Figure 7: The subtyping relationships in the clone example

method that is implemented by creating a new object of the class using the class’s copy constructorapplied toself.4 In the case of the derived classC, the copy constructor invokesB’s copy constructorto copy the fields defined byB. These include the fieldpvtX, which is not mentioned inB’s interface,and thus is hidden fromC.

It is instructive to look at the relationships between the various types in this example. Using thenotationBbody for the classB as seen from its body andBiface for the classB as seen through its interface,Figure 7 illustrates the various type relationships. Note that because of the hiding of thepvtX field,typeof(C) is not related totypeof(Bbody), but sincetypeof(C) is a subtype oftypeof(Biface),we are allowed to declare thatC inherits fromB.

If we were to replace the class types in this example with their corresponding object types (e.g.,typeof(C) for #C), the example would not typecheck because the type of thecopyB maker functionin B’s interface would be a subtype of its type inB’s body. This failure is what one would expect, sincean object oftypeof(Biface) is not guaranteed to have apvtX field in its implementation. Using classtypes, however, avoids this problem, since an object that has type#B is guaranteed to be implementedby classB (or one of its subclasses) and thus will have apvtX field in its representation.

4 An alternative extension

An alternative to the previous design is to allow inheritance-based subtyping even when the object-typeimplemented by the subclass is not a subtype of the parent class’s object type. More formally, thiscorresponds to dropping Clause 3 from the list in Section 3.1. Because this second form of inheritance-based subtyping admits more subtyping relationships, it isstrictly more expressive than the first. InSection 4.2 we give an example that demonstrates this greater expressiveness. All of the previousexamples of inheritance-based subtyping carry though without change.

We must also replace Clause 5 with a different approach because of a technical problem that wedescribe in Section 4.1. Instead of adding subsumption to the standard MOBY rules for method and

4Note that in MOBY, object constructors are calledmakers.

9

Page 10: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

class B {public meth m1 () -> Int { ... }public meth m2 ......

}class C {

inherits B : { public meth m2 ... }public meth m1 () -> Bool { ... }maker mkC of Unit { ... }...

}

Figure 8: Example of reusing a private method name

field selection, we add new judgements for the case where the argument has a class type.

4.1 Inheritance-based subtyping vs. privacy

There is a potential problem in our second extension’s type system involving the interaction betweeninheritance-based subtyping and MOBY’s support for privacy. Because MOBY allows signature as-cription to hide object members (e.g., theitems field in Figure 2),#C can be a subtype of#B evenwhentypeof(C) is not a subtype oftypeof(B). The problem arises in the case where classCdefines a method with the same name as a method that exists inB but is hidden fromC. Consider thecode fragment in Figure 8, for example. Given these definitions, how do we typecheck the expression:“(new mkC()).m1()?” If we allow subsumption on the left-hand side of the methodselection, thenthere are two incompatible ways to typecheck this expression. It is to avoid this ambiguity that wereplace Clause 5 in Section 3.1.

4.2 Encoding mixins

MOBY does not support any form of multiple inheritance, but with the combination of parameterizedmodules and class types, it is possible to encode mixins [BC90, FKF98]. In this encoding, a mixinis implemented as a class parameterized over its base class using a parameterized module. The classinterface of the base class contains only those components that are necessary for the mixin. Afterapplying the mixin to a particular base class, we create a newclass that inherits from the mixed baseclass and uses the class types to reconstitute the methods ofthe base class that were hidden as a resultof the module application. Without class types, it would notbe possible to make the original class’smethods visible again. For example, Figure 9 gives the encoding of a mixin class that adds aprintmethod to a class that has ashowmethod. After applyingPrintMix to classA, we define a classPrAthat reconstitutesA’s anotherMeth method. Notice that we need to use an explicit type constraintto convert the type ofself from #PrA to #A, since we do not have subsumption at method dispatch.While this encoding is cumbersome, it illustrates the powerof class types. Also, it might serve as thedefinition of a derived form that directly supports mixins.

This example will not typecheck under the more restrictive form of inheritance-based subtypingdescribed in Section 3. The problem is that the implicit signature of the parameterizedPrintMix

10

Page 11: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

signature HAS_SHOW {type InitBclass B : {meth show : Unit -> Stringmaker mk of InitB

}}module PrintMix (M : HAS_SHOW){

class Pr {inherits M.Bpublic meth print () -> Unit {

ConsoleIO.print(self.show())}maker mk (x : InitB) { super mk(x) }

}}

class A {public meth show () -> String { "Hi" }public meth anotherMeth () -> Unit { ... }maker mk () { }

}

module P = PrintMix({type InitB = Unit; class B = A})

class PrA {inherits P.Prpublic meth anotherMeth () -> Unit {(self : #A).anotherMeth()

}}

Figure 9: Encoding mixins in Extended MOBY

module declares that thePr class inherits from the formalM.B, which means thattypeof(Pr) mustbe a subtype of the object type of any class bound toM.B. The classA violates this requirement andthus the application of thePrintMixmodule will fail to typecheck.

5 XMOC

We have developed a functional object calculus, called XMOC, that models the type system of ExtendedMOBY and validates its design. XMOC supports both traditional structural subtyping and inheritance-based subtyping. In this section, we discuss the intuitionsbehind XMOC and state type soundnessresults. The full system and an outline of our soundness theorem appears in Appendices B, C, and D.

5.1 Syntax

The term syntax of XMOC is given in Figure 10. An XMOC program consists of a sequence of class

11

Page 12: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

p ::= d; pj ed ::= classC (x : �) fj b m = �mm2M jgj classC : � = C0b ::=j inheritsC(e);� ::= (�) fjinheritsB; m : �mm2M jg� ::= �j � ! � 0j obj�.fjm : �mm2M jgj #C� ::= (x : �)) ee ::= xj fn(x : �)) ej e(e0)j new C(e)j selfj e.mj self!statej e@C

Figure 10: Syntax of XMOC terms

declarations terminated by an expression. Each declaration binds aclass nameto a class definition; wedo not allow rebinding of class names. The set of class names includes the distinguished nameNone,which we use to denote the super-class of base classes. We follow the convention of usingC for classnames other thanNone andB for class names includingNone. Class declarations come in two forms.In the first, a classC is defined by extending an optional parent class (b) by overriding and addingmethods. When no parent is specified, we say thatC is abase-class; otherwise, we say thatC inheritsfrom its parent class. To model the notion of object state, weparameterize this form of class declarationby a variablex. When an object is created, the argument bound tox is included in the representation ofthe object as its state. In addition, if the class has a superclass,x may be used to compute the argumentto be passed to the superclass initialization function. Since an object’s implementation is spread overa hierarchy of classes, it has a piece of state for each class in its implementation. Methods defined ina given class may access the state for that class using the form self!state. In the second form ofclass declaration, a classC can be derived from an existing classC 0 by class-interface ascription, whichproduces a class that inherits its implementation fromC 0, but has a more restrictive class interface�. Aclass interface� specifies the type of the class’s state, the name of the nearest revealed ancestor class(orNone), and a typed list of available methods. The types of XMOC include type variables, functiontypes, recursive object types, and class types.

Each method (�) takes a single parameter and has an expression for its body.The syntax of expres-sions (e) includes variables, functions, function application, new object creation, the special variableself (only allowed inside method bodies), method dispatch, and access to the object’s state. The lastexpression form (e@C) is anobject-view coercion. Unlike Extended MOBY, XMOC does not mapthe inheritance relation directly to the subtyping relation; instead we rely on object-view coercions toexplicitly coerce the type of an expression from a class to one of its superclasses. This approach avoidsthe problem discussed in Section 4.1 without requiring two typing judgements for method dispatch. Itis possible to insert these coercions automatically into the XMOC representation of a program as partof typechecking (such a translation is similar to the type-directed representation wrapping that has beendone for polymorphic languages [Ler92]).

12

Page 13: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

5.2 Dynamic Semantics

Evaluation of an XMOC program occurs in two phases. The first phase is defined by theclass linkingrelation, writtenK; p� K0; p0, which takes adynamic class environmentK and links the left-most classdefinition inp to produce a new dynamic class environmentK0 and a residual programp. Class linkingterminates with a residual expression once all of the class declarations have been linked. The secondphase evaluates the residual expression to a value (assuming termination). This phase is defined by theexpression evaluation relation, which we write asK; e� K; e0. (We also use the notationK ` e ,! e0to emphasize that the dynamic class environment does not change during this phase.) Defining thesemantics of linking and evaluation requires extending theterm syntax with run-time forms.

Correctly handling class-interface ascription provides the greatest challenge in defining the seman-tics of XMOC. Using this mechanism, a public methodm in B can be made private in a subclassC,and subsequentlym can be reused to name an unrelated method in some descendant class ofC (recallthe example in Figure 8). Methods inherited fromB must invoke the originalm method when theysend them message toself, while methods defined inD must get the new version. We use a variationof the Riecke-Stone dictionary technique [RS98, FR99b] to solve this problem. Intuitively, dictionariesprovide the�-conversion needed to avoid capture by mapping method namesto slotsin method suites.To adapt this technique to XMOC, when we link a classC, we replace each occurrence ofself in themethods thatC defines with the object view expression “self @C.” Rule 5 in Appendix B describesthis annotation formally. At runtime, we represent each object as a pair of a raw object (denoted bymeta-variableobj ) and a view (denoted by a class name). The raw object consistsof the object’s stateand the name of its instantiating class; this class name is used to find the object’s method suite. The viewrepresents the visibility context in which a message send occurs; those methods in scope in the viewclass are available. To lookup methodm in runtime objecthobj ; Ci, we use the dictionary associatedwith C in the class environmentK to find the relevant slot. We use this slot to index into the methodsuite associated withobj . Rule 3 in Appendix B formally specifies method lookup.

5.3 Static semantics

The XMOC typing judgements are written with respect to a static environment�, which consists of aset of bound type variables (A), a subtype assumption map (S), a class environment (C), and a variableenvironment (V). We define these environments and give the complete set of XMOC typing judgementsin Appendix C. Here we briefly discuss some of the more important rules.

As mentioned earlier, each XMOC class name doubles as an object type. We associate such a typewith an object whenever we instantiate an object from a class, according to the typing rule(C of�)(C) = (�) fjinheritsB; m : �mm2M jg � ` e . � 0 � ` � 0 <: �� ` new C(e) . #Cwhich looks up classC in �, infers a type� 0 for the constructor argumente, and insures that this type isa subtype of the type of the class parameter� .

In contexts that allow subsumption, we can treat a class typeas an object type according to thefollowing subtyping judgement:� ` Ok (C of�)(C) = (�) fjinheritsB; m : �mm2M jg� ` #C <: obj�.fjm : �mm2M jg

13

Page 14: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

This rule exposes all the methods publicly available from classC because we install all such methodsin the class interface that we associate withC in �. This rule corresponds to the property that#C is asubtype oftypeof(C)in Extended MOBY.

Unlike Extended MOBY, we do not treat a class type#C as being a subtype of its superclass type.Instead we use an object view constraint, which is typed as follows:� ` e . #C 0 H(�) ` C 0 l C� ` e@C . #CThe judgementH(�) ` C 0 l C states thatC 0 inherits fromC in the class hierarchyH(�) (the meta-functionH projects the class hierarchy from the environment�). Because we do not treat inheritancedirectly as subtyping in XMOC, we only need one rule for typing method dispatch.� ` e . � � ` � <: obj�.fjm : �mm2M jg m 2M� ` e.m . �m[� 7! obj�.fjm : �mm2M jg]5.4 Soundness

We have proven the type soundness of XMOC. We outline this result here and give a more detaileddescription in Appendix D. We start with asubject reductiontheorem, which states that the evaluationrelation preserves the type of programs and class environments.

Theorem (Subject Reduction)If K is a closed dynamic class environment such that� ` K and for aclosed programp we have�;H(K) ` p . �f ; �f andK; p � K0; p0, then there exists an environment�0 and a type� 0, such that� �0;H(K0) ` p0 . �f ; � 0,� �0 ` � 0 <: �f , and� �0 ` K0Furthermore, ifp is an expression, then�f = �0.The proof has two steps: first we show that linking preserves types and produces a well-typed classenvironment, and then we show that expression evaluation preserves the type of expressions.

The next step is aprogresstheorem, which states that well-typed programs do not getstuck.

Theorem (Progress)If K is a closed dynamic class environment such that� ` K and for a programpwe have�;H(K) ` p . �f ; �f with p and�f both closed, then eitherp is a value or there existsK0 andp0 such thatK; p� K0; p0.Here we useH to project thedynamicclass hierarchy from the dynamic class environmentK.

Definition We say that a programp yieldsK0; p0 if ;; p � K0; p0 and there doesnot existK00; p00 suchthatK0; p0� K00; p00.

14

Page 15: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

Finally, we show the type soundness of XMOC.

Theorem (Type Soundness)If ; ` p . �f ; �f and p yields K0; p0, thenp0 is a valuew such that�f ;H(K0) ` w . � 0 with �f ` � 0 <: �f .

6 Related work

Our class types are motivated by the role that classes play in languages like C++ and JAVA . There areseveral differences, however, between Extended MOBY and these other languages. Extended MOBY

supports both inheritance-based and structural subtyping, whereas neither C++ or JAVA supports struc-tural subtyping. Another important difference is in the waythat abstraction is supported. MOBY andExtended MOBY allow partial hiding of inherited components using signature ascription, which meansthattypeof(C) may not be a subtype oftypeof(B) even whenC is known to inherit fromB (seeSection 4.1). JAVA does not support private inheritance, but C++ allows a class toprivately inherit fromanother class. In that case, all of the base-class members are hidden and there is no subtyping relation-ship. Extended MOBY is more flexible, since it allows hiding to be done on a per-member basis. It alsoallows the class hierarchy to be hidden by omitting theinheritsclause in class interfaces. In C++ andJAVA the full class hierarchy is manifest in the class types (except for C++’s private inheritance).

Fisher’s Ph.D. dissertation [Fis96] is the earliest formalization of class types that we are aware of.In her work, each implementation is tagged with a row variable using a form of bounded existentialrows. In our work, we adopt classes as a primitive notion and use the names of such classes in a fashionanalogous to Fisher’s row variables. A weakness of the earlier work is its treatment of private names; itprovides no way to hide a method and then later add an unrelated method with the same name.

Our use of dictionaries to specify the semantics of method dispatch in the presence of privacy isadapted from the work of Riecke and Stone [RS98]. The main difference is that XMOC has an explicitnotion of class and we introduce dictionaries as a side-effect of linking classes.

More recently, Igarashiet al. have describedFeatherweight Java, which is an object calculus de-signed to model the core features of JAVA ’s type system [IPW99]. Like our calculus, FeatherweightJava has a notion of subtyping based on class inheritance. Our calculus is richer, however, in that itmodels private members and narrowing of class interfaces. In addition, we have a notion of structuralsubtyping, and we relate the inheritance-based and structural subtyping notions.

The notion of type identity based on implementation was present in the original definition ofStan-dard ML in the form ofstructure sharing[MTH90]. The benefits of structure sharing were fairly limitedand it was dropped in the 1997 revision of SML [MTHM97].

7 Conclusion

This paper presents an extension to MOBY that supports classes as types and inheritance-based subtyp-ing. We have described two alternative type systems for thisextension and have illustrated its utilitywith a number of examples. These alternatives are distinguished by when they allow a subclass to beviewed as a subtype of its parent class. Our first design restricts inheritance-based subtyping to those

15

Page 16: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

situations where the object type implemented by the subclass is a subtype of the object type imple-mented by its superclass. Our second design relaxes this restriction at the cost of more complicatedrules for typing method and field selection and of requiring explicit type coercions in some situations.While the latter system is more expressive, and there are plausible examples of the usefulness of theextra expressiveness, we believe that the former design is abetter choice for integrating into MOBY.

We believe that Extended MOBY is the first design that incorporates types for objects that rangefrom class types to structural object types.5 While this flexibility goes beyond what is found in otherlanguages, the most interesting aspect of the design is the interaction between privacy (specified viamodule signature matching) and inheritance-based subtyping. Because our second design allows theinherits relation between two class types to be visible evenwhen their corresponding object types arenot in a subtyping relationship, one can use such class typesto recover access to hidden methods. Thisproperty enables more flexible use of parameterized modulesin combining class implementations, asillustrated in Section 4.2.

We have also developed a formal model of this extension and have proven type soundness for it.We are continuing to work on improving our formal treatment of class types and implementation-basedinheritance. One minor issue is that XMOC requires that class names be unique in a program; this re-striction can be avoided by introducing some mechanism, such asstamps, to distinguish top-level names(e.g., see Leroy’s approach to module system semantics [Ler96]).We would also like to generalize therule that relates class types with object types (rule 36 in Appendix C) to allow positive occurrences of#C to be replaced by the object type’s bound type variable. While we believe that this generalization issound, we have not yet proven it.

References

[AG98] Arnold, K. and J. Gosling.The Java Programming Language. Addison-Wesley, Reading, MA, 2ndedition, 1998.

[BC90] Bracha, G. and W. Cook. Mixin-based inheritance. InECOOP’90, October 1990, pp. 303–311.

[BCC+96] Bruce, K., L. Cardelli, G. Castagna, The Hopkins Object Group, G. Leavens, and B. Pierce. Onbinary methods.TAPOS, 1(3), 1996, pp. 221–242.

[Fis96] Fisher, K.Type Systems for Object-oriented Programming Languages. Ph.D. dissertation, StanfordUniversity, August 1996.

[FKF98] Flatt, M., S. Krishnamurthi, and M. Felleisen. Classes and mixins. InPOPL’98, January 1998, pp.171–183.

[FR99a] Fisher, K. and J. Reppy. The design of a class mechanism for Moby.In PLDI’99, May 1999, pp.37–49.

[FR99b] Fisher, K. and J. Reppy. Foundations for MOBY classes.Technical Memorandum, Bell Labs, LucentTechnologies, Murray Hill, NJ, February 1999.

[IPW99] Igarashi, A., B. Pierce, and P. Wadler. Featherweight Java: A minimal core calculus for Java andGJ. InOOPSLA’99, November 1999, pp. 132–146.

5JAVA is close to Extended Moby in this respect, but interface subtyping relations in JAVA must be declared ahead of timeby the programmer, whereas object-type subtyping in MOBY is based on the structure of the types.

16

Page 17: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

[KLM94] Katiyar, D., D. Luckham, and J. Mitchell. A type system for prototyping languages. InPOPL’94,January 1994, pp. 138–161.

[Ler92] Leroy, X. Unboxed objects and polymorphic typing. InPOPL’92, January 1992, pp. 177–188.

[Ler96] Leroy, X. A syntactic theory of type generativity and sharing.JFP, 6(5), September 1996, pp. 1–32.

[MTH90] Milner, R., M. Tofte, and R. Harper.The Definition of Standard ML. The MIT Press, Cambridge,MA, 1990.

[MTHM97] Milner, R., M. Tofte, R. Harper, and D. MacQueen.The Definition of Standard ML — Revised 1997.The MIT Press, Cambridge, MA, 1997.

[PT93] Pierce, B. C. and D. N. Turner. Statically typed friendly functions via partially abstract types.Technical Report ECS-LFCS-93-256, University of Edinburgh, LFCS, April 1993. Also available asINRIA-Rocquencourt Rapport de Recherche No. 1899.

[RS98] Riecke, J. G. and C. Stone. Privacy via subsumption. InFOOL5, January 1998. A longer versionwill appear in TAPOS.

[Str97] Stroustrup, B.The C++ Programming Language. Addison-Wesley, Reading, MA, 3rd edition, 1997.

A A brief introduction to M OBY

This appendix provides a brief introduction to some of MOBY’s features to help the reader understandthe examples in the paper. A more detailed description of MOBY object-oriented features can be foundin [FR99a].

MOBY programs are organized into a collection ofmodules, which havesignatures. A module’ssignature controls the visibility of its components. Signatures are the primary mechanism for data andtype abstraction in MOBY. To support object-oriented programming, MOBY providesclassesandobjecttypes. The following example illustrates these features:

module M : {class Hi : {

public meth hello : Unit -> Unitpublic maker mk of String

}val hi : typeof(Hi)

} {fun pr (s : String) -> Unit { ConsoleIO.print s }class Hi {

field msg : Stringpublic meth hello () -> Unit {

pr "hello "; pr self.msg; pr "\n"}public maker mk (s : String) { field msg = s }

}val hi : typeof(Hi) = new mk "world"

}

This code defines a moduleM that is constrained by a signature with two specifications: the classHiand the valuehi. The interface of theHi class specifies that it has two public components: a method

17

Page 18: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

hello and a makermk (“maker” is the MOBY name for constructor functions). The signature specifiesthathi is an object; the type expression “typeof(Hi)” denotes the object type induced by readingoff the public methods and fields of the classHi. It is equivalent to the object type definition

objtype HiTy { meth hello : Unit -> Unit }

The body ofM defines a functionpr for printing strings, and the definitions ofHi andhi. Sincepr is not mentioned in the signature ofM, it is not exported. Note that theHi class has a fieldmsgin its definition. Since this field does not have apublic annotation, it is only visible to subclasses.Furthermore, sincemsg is not mentioned inM’s signature, it is not visible to subclasses ofHi outsideof M. Thus, themsg field is protectedinsideM and isprivateoutside. This example illustrates MOBY’suse of module signatures to implement private class members.

B Dynamic Semantics of XMOC

B.1 Notation

If A andB are two sets, we writeA n B for the set difference andA t B if they aredisjoint. We use

the notationA fin! B to denote the set of finite maps fromA toB. We writefa1 7! b1; : : : ; an 7! bngfor the finite map that mapsa1 to b1, etc. For a finite mapf , we write dom(f) for its domain and rng(f)for its range. Iff andg are finite maps, we writef�g for the finite mapfx 7! g(x) j x 2 dom(g)g [ fx 7! f(x) j x 2 dom(f) n dom(g)gandf# A for the restriction off ’s domain to the setA. We writet[x 7! t0] for thecapture-freesubsti-tution of t0 for x in the termt.B.2 Syntax

We use the following classes of identifiers in the syntax of XMOC.� 2 TYVAR type variables� 2 TYPE types� 2 INTERFACE class interfacesB;C 2 CLASSNAME = fNone; : : : g class names#B;#C 2 CLASSTYPE class typesm 2 METHNAME method namesM 2 Fin(METHNAME) method name setsx 2 VAR variables� 2 METHBODY method bodiese 2 EXP expressionsobj 2 OBJEXP object expressions

We follow the convention of usingC when referring to a class name other thanNone.

Figure 11 describes the full syntax of XMOC. In this grammar,we mark the run-time forms witha (�) on the right. The formhobj ; Ci denotes a dynamic object. Theobj portion, which we refer toas araw object, stores the object’s state and the name of its defining class.TheC portion indicates the

18

Page 19: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

p ::= d; pj ed ::= classC (x : �) fj b m = �mm2M jgj classC : � = C0� ::= (�) fjinheritsB; m : �mm2M jg� ::= �j � ! � 0j obj�.fjm : �mm2M jgj #Bb ::=j inheritsC(e);� ::= (x : �)) ee ::= xj fn(x : �)) ej e(e0)j new C(e)j selfj e!statej e@Cj e.mj hobj ; Ci (�)obj ::= C :: fj e; obj jg (�)None (�)C(e) (�)

Figure 11: The full syntax of XMOC

currentviewof the object, which encodes the object’s visibility context. Only those methods visible inclassC are available in the current context.

During evaluation, we use several syntactic forms to denoteraw objects. In the first such form,C :: fj e; obj jg, classC is the instantiating class of the object,e denotes its local state, andobj representsthe portion of the object inherited from its parent class. The methods associated with classC are foundin the dynamic class environment, defined below. The second such form,None, is used to denotethe inherited portion of raw objects that were not defined viainheritance. The third formC(e) is usedduring evaluation to specify the computation that initializes the portion of a raw object defined in classC. Expressione denotes the argument to this initialization function.

B.3 Evaluation

To define the evaluation relation, we need some additional definitions:

SLOT method suite slots� 2 DICT = METHNAMEfin! SLOT dictionaries�T 2 METHSUITE = SLOTfin! METHBODY method suitesH 2 HIERARCHY = CLASSNAME

fin! CLASSNAME class hierarchy

A dictionary � is a one-to-one finite function from method names to slots. Wesay that� is a slotassignmentfor a set of method namesM if and only if dom(�) = M . A method suiteis a finitefunction from slots to method bodies. A class hierarchy describes the inheritance relationship betweenclasses by mapping each class name to the name of its superclass.

The dynamic semantics is split into two phases; the first phase links class declarations to producea dynamic class environment and a residual expression. The dynamic class environment maps eachclass name in its domain to a tuple that stores the name of the parent class, a constructor expression forinitializing instantiated objects, a method suite, and a dictionary.K 2 DYNCLASSENV = CLASSNAME

fin! (CLASSNAME � EXP� METHSUITE� DICT)We write the linking relation asK; p � K0; p0. The second phaseevaluatesthe residual expressionusing the dynamic class environment to instantiate objectsand resolve method dispatch. The evaluation

19

Page 20: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

relation is written formally asK; e � K; e0, but we abbreviate this notation toK ` e ,! e0 whenconvenient.

B.4 Dynamic Class Hierarchy

We construct the dynamic class hierarchy from the dynamic class environmentK as follows:H(K) = fC 7! B j C 2 dom(K) andK(C) = (B; ; ; )gB.5 Evaluation Contexts and Values

We specify the dynamic semantics using the standard technique of evaluation contexts. We distinguishtwo kinds of contexts in the specification of the evaluation relation: expression contexts, E, andobjectinitialization contexts, F . The syntax of these contexts is as follows:E ::= [ ] j E(e) j w(E) j new C(E) j E!state j E@C j E.m j hF; CiF ::= [ ] j C(E) j C :: fjE; obj jg j C :: fjw; F jgWe also define the syntactic classes ofvalues(w) andraw object values(ov ) by the following grammar:w ::= fn(x : �)) e j hov ; Ciov ::= None j C :: fjw; ov jgB.6 Field lookup

We use the auxiliaryfield lookuprelationCv ` C :: fjw; ov jg ;f w0 to specify the semantics of stateselection. In this judgement form, the class name on the leftof the turnstile denotes the visibility contextof the field selection operation.C ` C :: fjw; ov jg;f w (1) Cv 6= C Cv ` ov ;f w0Cv ` C :: fjw; ov jg;f w0 (2)

In the first of these rules, the defining class of the raw objectmatches the context class. Hence the valuew is the state we are looking for. In the second rule, the classes don’t match. In this case, the desiredstate must have been defined by a parent class, so we continue our search with the parent raw object,ov .

B.7 Method lookup

We define the auxiliarymethod lookuprelationK ` hov ; Cvi.m;m w, which specifies how methoddispatching is resolved, as follows:K(Cv) = ( ; ; ; �) K(C) = ( ; ; �T ; ) �T (�(m)) = (x : �)) eK ` hC :: fjw; ov jg; Cvi.m;m fn(x : �)) e[self 7! C :: fjw; ov jg] (3)

20

Page 21: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

In this rule,Cv is the view of the object being sent the messagem, while C is the class that definedthe object. We useCv to index into the dynamic class environment to retrieve the method dictionary�associated with classCv. The method names in the domain of this dictionary are the methods currentlyavailable from the object. We use classC to access the method suite�T associated withC. The methodbodies stored in�T are the implementations provided by the object. We lookup the slot associated withmethod namem in �, and then index into�T using that slot to obtain the desired method body. The typesystem insures that the range of� is a subset of the domain of�T . We convert the method body into afunction and replace all occurrences ofself with the receiver object. We return the resulting expression.

B.8 Class linking

The evaluation relation for class linking is defined by the following three rules, which each link one classdeclaration into the dynamic class hierarchy. The first ruledescribes the case of a base-class declaration.Since a base class has no superclass, the tuple associated with this class storesNone as the name ofthe parent class and does not require a parent initialization expression. It constructs the method suitefrom the method bodies defined in the class, first rewriting all occurrences ofself to self @C to set theappropriate view for invocations throughself .K; classC (x : �) fj m = �mm2M jg; p � K�fC 7! (None; –; �T ; �)g; p

where �m = �m[self 7! self @C]� is a slot assignment forM .�T = f�(m) 7! �mjm 2Mg (4)

The second rule handles the case of a subclass declaration. This rule constructs the dictionary for thenew class (C) by augmenting the dictionary of the parent class (C 0) with fresh slot assignments fornewly defined methods (those inM n dom(�C0)). It constructs the method suite forC by extendingtheC 0 suite with mappings from the freshly allocated slots to the new method bodies and replacing themethod bodies for overridden methods.K;classC (x : �) fjinheritsC0(e); m = �mm2M jg; p� K�fC 7! (C0; fn(x : �)) e; �TC ; �C)g; p

where K(C0) = ( ; ; �TC0 ; �C0)� is a slot assignment forM n dom(�C0) such that rng(�) t dom(�TC0 )�C = �C0 [ ��m = �m[self 7! self @C]�TC = �TC0�f�C(m) 7! �mjm 2Mg (5)

The third linking rule describes class signature ascription. This declaration hides the portions of theC 0class not explicitly mentioned in the class signature. Dynamically, we capture this behavior by adoptingfor C the dictionary associated withC 0 after all but the methods inM have been removed from itsdomain. K; classC : (�) fjinheritsB; m : �mm2M jg = C0; p� K�fC 7! (C0; fn(x : �)) x; �TC ; �C)g; p

where K(C0) = ( ; ; �TC0 ; �C0)�TC = �TC0�C = �C0#M (6)

B.9 Expression evaluation

The following rules specify the semantics of expression evaluation. We use the notationK ` eo ,! eo0(where meta-variableeo ranges over eithere or obj ) as a shorthand for the notationK; eo � K; eo0when the run-time environment doesn’t change.

21

Page 22: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

K ` E[fn(x : �)) e(w)] ,! E[e[x 7! w]] (7)K ` E[new C(w)] ,! E[hC(w); Ci] (8)K ` E[hov ; Cvi!state] ,! E[w] whereCv ` ov ;f w (9)K ` E[hov ; Cvi@C0v] ,! E[hov ; C0vi] (10)K ` E[w.m] ,! E[w0] whereK ` w.m;m w0 (11)K ` F [C(w)] ,! F [C :: fjw; obj jg]where obj = � None if K(C) = (None; ; ; )C0(e(w)) if K(C) = (C0; e; ; ) (12)

C Typing rules for XMOC

The typing rules for XMOC are written with respect to an environment�, which has four parts:A 2 TYVARSET = Fin(TYVAR) bound type variablesS 2 SUBTYENV = TYVARfin! TYPE subtyping assumptionsC 2 CLASSENV = CLASSNAME

fin! INTERFACE class typing environmentV 2 VARENV = VARfin! TYPE variable typing environment� 2 ENV = TYVARSET� SUBTYENV � CLASSENV � VARENV typing environment

C.1 Static Class Hierarchy

We construct the static class hierarchy from the environment � as follows:H(�) = f(C 7! B) j (C of�)(C) = (�) fjinheritsB; m : �mm2M jggC.2 Judgement forms

The XMOC type system uses the following judgement forms:

22

Page 23: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

� ` � . Ok Type� is well-formedw.r.t.�. (rules 13–17)� ` � . Ok Class interface� is well-formedw.r.t.�. (rule 18)H ` Ok Class hierarchyH is well-formed. (rule 19)� ` Ok Environment� is well-formed. (rule 20)� ` � = � 0 Type� is equalto � 0. (rules 21–26)H ` B1 l B2 ClassB1 inheritsfromB2. (rules 27–30)� ` � <: � 0 Type� is asubtypeof � 0. (rules 31–36)� ` � <: �0 Class interface� is asubtypeof �0. (rule 37)� ` p . �0; � Programp definesenvironment�0 andhas type� . (rules 38–39)� ` d . �0 Declarationd definesenvironment�0. (rules 40–42)� ` � . � Method� has type� . (rule 43)� ` e . � Expressione has type� . (rules 44–51)�;H ` obj . #B Parent classobj has class type#B. (rules 52–54)�;H ` e . � Run-time expressione has type� . (rules 53 and 56)�;H ; C ` con . � Constructorcon, associated with classC, has interface�. (rules 57–58)� ` K Static environment� typesdynamic class environmentK. (rule 59)

C.3 Well-formedness judgements� ` Ok � 2 (A of�)� ` � . Ok (13)� ` Ok� ` #None . Ok (14)� ` � . Ok � ` � 0 . Ok� ` � ! � 0 . Ok (15)

� ` Ok #C 2 dom(C of�)� ` #C . Ok (16)� ` Ok 8m 2M � [ f�g ` �m . Ok� ` obj�.fjm : �mm2M jg . Ok (17)� ` � . Ok � ` #B . Ok 8m 2M � ` �m . Ok� ` (�) fjinheritsB; m : �mm2M jg . Ok (18)8C 2 dom(H ) H(C) 2 dom(H ) [ fNonegH ` Ok (19)8� 2 rng(S of�) � ` � . Ok8� 2 rng(C of�) � ` � . Ok8� 0 2 rng(V of�) � ` � 0 . Ok� ` Ok (20)

C.4 Equality judgements� ` � . Ok� ` � = � (21) � ` � 0 = �� ` � = � 0 (22)

23

Page 24: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

� ` � = � 0 � ` � 0 = � 00� ` � = � 00 (23)� ` �1 = �2 � ` � 01 = � 02� ` �1 ! � 01 = �2 ! � 02 (24)M0 =M 8m 2 M � [ f�g ` �m = � 0m� ` obj�.fjm : �mm2M jg = obj�.fjm : � 0mm2M0 jg (25)� ` obj�.fjm : �mm2M jg . Ok� ` obj�.fjm : �mm2M jg= obj�.fjm : �m[� 7! obj�.fjm : �mm2M jg]m2M jg (26)

C.5 Class hierarchy judgementsB 2 dom(H ) [ fNonegH ` B l B (27)C 2 dom(H )H ` C l None (28)H ` B1 l B2 H ` B2 l B3H ` B1 l B3 (29)H (C) = BH ` C l B (30)

C.6 Subtyping judgements� ` � = � 0� ` � <: � 0 (31)� ` � <: � 0 � ` � 0 <: � 00� ` � <: � 00 (32)� ` Ok � 2 dom(S of�)� ` � <: S(�) (33)� ` �2 <: �1 � ` � 01 <: � 02� ` �1 ! � 01 <: �2 ! � 02 (34)M0 �M �0 62 FV(obj�.fjm : �mm2M jg)8m 2 M0 � 62 FV(� 0m) and(� [ f�0g)�f� 7! �0g ` �m <: � 0m� ` obj�.fjm : �mm2M jg <: obj�0.fjm : � 0mm2M0 jg (35)� ` Ok (C of�)(C) = (�) fjinheritsB; m : �mm2M jg� ` #C <: obj�.fjm : �mm2M jg (36)� ` � 0 <: � H ` B l B0 M0 �M 8m 2 M0 � ` �m = � 0m8m 2 (MnM0) � ` �m . Ok� ` (�) fjinheritsB; m : �mm2M jg <: (� 0) fjinheritsB0; m : � 0mm2M0 jg (37)

24

Page 25: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

C.7 Typing judgements

As a notational convenience, we define the argument type of a classC in an environment� (writtenArgTy(�; C)) to be� if �(C) = (�) fjinheritsB; m : �mm2M jg.� ` d . �0 �0 ` p . �00; �� ` d; p . �00; � (38)� ` e . �� ` e . �; � (39)C 62 dom(C of�) � ` � . Ok�0 = ��fC 7! (�) fjinheritsNone; m : �mm2M jgg8m 2 M �0�fself 7! #Cg ` �m . � 0m �0 ` � 0m <: �m� ` classC (x : �) fj m = �mm2M jg . �0 (40)C 62 dom(C of�)(C of�)(C0) = (� 0) fjinheritsB0; m : � 0mm2M0 jg�0 = ��fC 7! (�)fj inheritsC0; m : � 0mm2(M0nM) m : �mm2M jgg�0�fx 7! �g ` e . � 00 �0 ` � 00 <: � 08m 2 (M\M0) �0 ` �m <: � 0m8m 2 M �0�fself 7! #Cg ` �m . � 00m �0 ` � 00m <: �m� ` classC (x : �) fjinheritsC0(e); m = �mm2M jg . �0 (41)C 62 dom(C of�) �0 = ��fC 7! �g �0 ` (C of�)(C0) <: �� ` classC : � = C0 . �0 (42)��fx 7! �g ` e . � 0� ` (x : �)) e . � ! � 0 (43)

� ` Ok (V of�)(x) = �� ` x . � (44)� ` Ok (V of�)(self) = �� ` self . � (45)��fx 7! �g ` e . � 0� ` fn(x : �)) e . � ! � 0 (46)� ` e . � 0 ! � � ` e0 . � 00 � ` � 00 <: � 0� ` e(e0) . � (47)� ` e . � 0 � ` � 0 <: ArgTy(�; C)� ` new C(e) . #C (48)� ` e . #C� ` e!state . ArgTy(�; C) (49)

� ` e . #C0 H(�) ` C0 l C� ` e@C . #C (50)� ` e . � m 2 M � ` � <: obj�.fjm : �mm2M jg� ` e.m . �m[� 7! obj�.fjm : �mm2M jg] (51)

25

Page 26: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

C.8 Typing rules for run-time forms

The typing rules for the run-time forms include rules 43 through 51 augmented with a dynamic classhierarchyH on the left-hand side of the turnstile. Rules 40 through 42 return an augmented classhierarchy in addition to an augmented static environment. In each case, the augmented hierarchy is justthe old one extended with a mapping from the newly declared class name to the name of its parent (orNone for base classes). In addition, rule 50 is replaced by rule 55. The remaining rules are given below.�;H ` e . � 0 � ` � 0 <: ArgTy(�; C)�;H ` C(e) . #C (52)H (C) = B �;H ` obj . #B �;H ` e . � 0 � ` � 0 <: ArgTy(�; C)�;H ` C :: fj e; obj jg . #C (53)� ` Ok K ` Ok�;H ` None . #None (54)�;H ` e . #C0 H ` C0 l C�;H ` e@C . #C (55)

�;H ` obj . #C0 H ` C0 l C�;H ` hobj ; Ci . #C (56)� = (�) fjinheritsNone; m : �mm2M jgM = dom(�) rng(�) � dom(�T )8m 2 M ��fself 7! #Cg;H ` �T (�(m)) . � 0m� ` � 0m <: �m�;H ; C ` (None; ; �T ; �) . � (57)� = (�) fj inheritsC0; m : �mm2M jg�(C0) = (� 0) fjinheritsB0; m : � 0mm2M0 jg�;H ` e . � ! � 00 � ` � 00 <: � 0M = dom(�) rng(�) � dom(�T )8m 2 M ��fself 7! #Cg;H ` �T (�(m)) . � 00m� ` � 00m <: �m8m 2 M\M0 � ` �m <: � 0m�;H ; C ` (C0; e; �T ; �) . � (58)

dom(K) = dom(C of�)8C 2 dom(K) �(C) = � and�;H (K); C ` K(C) . �0 and� ` �0 <: �� ` K (59)

D Proofs

The proof of soundness proceeds via a standard subject reduction argument,i.e., we first prove thatevaluation preserves types in Theorem 1 and then show that nowell-typed program can get stuck in

26

Page 27: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

Theorem 2. Consequently, well-typed programs either diverge or yield a value of the appropriate type(Theorem 3).

The subject reduction proof breaks into two pieces. In the first, we show that linking in a new classdeclaration (using Rule 4, 5, or 6) preserves the program type and produces a well-typed dynamic classenvironment. The challenge in this portion of the proof is toshow that the new class environment iswell-typed. These cases follow directly from an analysis ofthe reduction rules.

In the second part, we show that evaluating the program expression preserves its type. This portionfollows the standard pattern for establishing subject reduction. In particular, we show in Lemma 1 thatevery closed expression can be factored uniquely into an evaluation context and a redex. Lemma 2 showsthat evaluation does not introduce any free variables, so that if we start with a closed program, everyintermediate program during reduction will be closed, and hence may be factored into an evaluationcontext and a redex. Lemma 3 proves that if we have typed an expression and that expression has beendivided into an evaluation context and a redex, then we may also type the redex in the context that wetyped the original expression. Furthermore, if we replace the redex with another expression with a better(in the sense of subtyping) type, then the new expression will have a better type than the original. Thislemma means that we may prove the second piece of our subject reduction theorem by showing for eachreduction rule (Rules 7 to 12) that the type of the reduct on the right-hand side of the rule is better thanthe type of the redex on the left-hand side. For Rule 7, this property follows from a standard substitutionlemma (Lemma 4). For Rules 9 and 11, this property follows from Lemmas 5 and 6, respectively. Theremaining cases are straightforward.

The proof of progress also breaks into two pieces. The first piece shows that well-typed programs donot get stuck during linking, while the second shows that well-typed expressions do not get stuck duringevaluation. The linking piece proceeds by a case analysis onthe rule used to link in the pending class.The expression piece proceeds by induction on the typing derivation used to infer that the expressionwas well-typed.

Type soundness follows from Theorem 1 and Theorem 2.

In the remainder of this section, we formally state the definitions and major lemmas and theoremsnecessary to prove our subject reduction progress, and typesoundness theorems.

Definition 1 (Closure)� We say that an expression forme or an object formobj is closed if it contains no free variables.We say that it isself -closedif it is closed and does not contain the special symbolself .� A class declaration is closed if its method bodies contain nofree variables and any initializationexpression isself -closed after that expression is converted to a function from the class parameter.� A program is closed if its class declarations are closed and its final expression isself -closed.� A dynamic class environmentK is closed if for allC 2 dom(K), if K(C) = ( ; e; �T ; ), thene is self -closed and for alli 2 dom(�T ), �T (i) is closed.

To state our unique decomposition lemma, we need to define expression redeces (er) and objectredeces (or).

27

Page 28: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

er ::= w1(w2) j new C(w) j w!state j w@C j w.m j hov ; Cior ::= C(w) j C :: fjw; ov jgIn the following lemma, we use the symbol� to denote syntactic equality.

Lemma 1 (Unique Decomposition)� If e is a self -closed expression, then eithere is a valuew or there exists a unique evaluationcontextE and redexer such thate � E[er].� If obj is aself -closed raw object, then eitherobj is a valueov or there exists a unique evaluationcontextF and redexor such thatobj � F [or].

The proof is by mutual induction on the structure ofe andobj .Lemma 2 (Evaluation Preserves Closure)If K andp are both closed andK; p� K0; p0, thenK0 andp0 are both closed as well.

The proof is by a case analysis on the rule used to derive the reductionK; p� K0; p0.Lemma 3 (Context) If we may derive the judgement�;H ` G[e] . � , where the meta-variableGranges over eitherE or F , then for some type�g, we may also derive the judgement�;H ` e . �g.Furthermore, if the judgement�;H ` e0 . � 0g is also derivable, where� ` � 0g <: �g, then we may derive�;H ` G[e0] . � 0, where� ` � 0 <: � .

The proof is by induction on the derivation of�;H ` G[e] . � .

Lemma 4 (Substitution) If we may derive the judgements��fx 7! �ag;H ` e . � and�;H ` e0 .� 0a, and� ` � 0a <: �a, then we may also derive the judgement�;H ` e[x 7! e0] . � 0, where� ` � 0 <: � .

The proof is by induction on the derivation of��fx 7! �ag;H ` e . � .

Lemma 5 (State Selection)If we may derive the judgements�;H ` obj . #C 0 andC ` obj ;f w,then we may derive the judgements�;H ` w . � and� ` � <: ArgTy(�; C).The proof is by induction on the derivation ofC ` obj ;f w.

Lemma 6 (Method Selection) If we may derive the judgements� ` K and�;H(K) ` w.m . � andK ` w.m;m w0, then we may also derive the judgements�;H(K) ` w0 . � 0 and� ` � 0 <: � .

This proof is the crux of the subject reduction theorem. Hence, we describe its structure in some detail.To have derived the judgementK ` w.m;m w0, we must have determined that� w = hC :: fjws; ov jg; Cvi,� K(C) = ( ; ; �TC ; ),

28

Page 29: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

� K(Cv) = ( ; ; ; �v), and� w0 = �TC(�v(m))[self 7! C :: fjws; ov jg]To have derived the judgement�;H(K) ` w.m . � , we must have derived the judgements� H(K) ` C l Cv,� � ` #Cv <: obj�.fjm : �mm2M jg, and� �;H(K) ` C :: fjws; ov jg . #CFurthermore, it must be the case that� is syntactically equivalent to�m[� 7! obj�.fjm : �mm2M jg].Let Cv � C0; : : : ; CN � C be the inheritance chain fromCv to C in K. Let CL be the class in thechain the furthest fromCv such that�v(m) = �L(m), where�L is the dictionary thatK associates withclassCL. Note thatCL can be equal toCv, C, or both. By the construction of method tables duringclass linking, it must be the case that�TC(�v(m)) = �TL(�v(m))= �TL(�L(m))Since� ` K, we must have derived the judgement��fself 7! #CLg;H(K) ` �TL(�L(m)) . �L00m ,where�L00m is the type inferred by Rule 58 for methodm in classCL. By tracing the necessary subtypingand equality relations through Rules 36, 37, 58, and 59, we may determine that� ` �L00m <: �m[� 7! obj�.fjm : �mm2M jg]By the construction of method suites, all occurrences ofself in �TL(�L(m)) appear in the formself @C 0, whereC 0 is some ancestor class ofC. Consequently, we may derive via a modified sub-stitution lemma the following judgement:�;H(K) ` �TL(�L(m))[self 7! C :: fjws; ov jg] . �L00mwhich is what we needed to show.

Theorem 1 (Subject Reduction)If K is a closed dynamic class environment such that� ` K and fora closed programp we have�;H(K) ` p . �f ; �f andK; p� K0; p0, then there exists an environment�0 and a type� 0, such that� �0;H(K0) ` p0 . �f ; � 0,� �0 ` � 0 <: �f , and� �0 ` K0Furthermore,p0 is closed and ifp is an expression, then�f = �0.The proof proceeds by a case analysis on the reduction rule used to deriveK; p� K0; p0.

29

Page 30: Inheritance-based subtypingpdfs.semanticscholar.org/742a/32dd41d6f9ed4ca31ea6... · with inheritance-based subtyping relations. In addition, we present a typed object calculus that

Theorem 2 (Progress)If K is a closed dynamic class environment such that� ` K and for a programp we have�;H(K) ` p . �f ; �f with p and�f both closed, then eitherp is a value or there existsK0andp0 such thatK; p� K0; p0.The proof is by induction on the derivation of�;H(K) ` p . �f ; �f .

Definition 2 We say that a programp yieldsK0; p0 if ;; p� K0; p0 and there doesnotexistK00; p00 suchthatK0; p0� K00; p00.Theorem 3 (Type Soundness)If ; ` p . �f ; �f andp yieldsK0; p0, thenp0 is a valuew such that�f ;H(K0) ` w . � 0 with �f ` � 0 <: �f .

The proof is by induction on the number of steps needed to produceK0; p0.

30