<<

Inclusive vs. Coercive Relationships • Inclusive – Every cat is a feline – Every dog is a canine – Every feline is a mammal • Coercive/isomorphism COS 441 – Integers can be converted into floating point numbers Princeton University – Booleans can be converted into interegers – Mammals with a tail can be converted to a mammals Fall 2004 without a tail (ouch!)

Subtype Relation Implicit vs Explicit

τ τ τ τ τ Read 1 <: 2 as 1 is a subtype of 2 or 2 is Typing rules for subtyping can be rendered τ a supertype of 1 in either implicit or explicit form Subtype relation is reflexive and transitive τ τ τ τ refl 1 <: 2 2 <: 3 τ <: τ τ τ trans 1 2 1 <: 3

τ τ τ τ τ τ cast We say ( 1 = 2) iff ( 1 <: 2) and ( 2 <: 1)

Simplification for Type-Safety Dynamic

• Inclusive/Coercive distinction independent • For inclusive system primitives must of Implicit/Explicit distinction operate equally well for all subtypes of a • Harper associates inclusive with implicit give type for which the primitive is defined typing and coercive with explicit typing • For coercive systems dynamic semantics because it simplifies the type safety proof simply must cast/convert the value – You can have a inclusive semantics with appropriately explicit type casts – You can have a coercive semantics with implicit typing

1 Varieties of Systems Subtype Relation (cont.)

• Implicit, Inclusive – Described by Harper Given

• Explicit, Coercive – Described by Harper b2i i2f bool <: int int <: float • Implicit, Coercive – Non-deterministic insertion of coercions via transitivity we can conclude • Explicit, Inclusive – Type casts are no-ops (bool <: float ) in the operational semantics

Subtyping of Functions Subtyping Quiz

→ → weight: mammal → float mammal int <: mammal float → → numberOfTeeth: mammal → int feline int <: feline float → → numberOfWiskers: feline → int mammal float <: feline float → → pitchOfMeow: feline → float mammal int <: feline int → → printInfo: (mammal * mammal int <: feline float (mammal → float)) → unit printFelineInfo: (feline * (feline → float)) → unit

Co/Contra Variance Width vs Depth Subtyping

argument is contravariant return type is covariant τ τ Consider the n-tuple ( 1 * … * n) τ τ τ τ Width Subtyping 1’ <: 1 2 <: 2’ τ τ τ τ 1 → 2 <: 1’ → 2’ (int * int * float ) <: ( int * int ) m > n width (τ * … * τ ) <: (τ * … * τ ) both are covariant 1 m 1 n Depth Subtyping τ <: τ ’ τ <: τ ’ 1 1 2 2 (int * int ) <: ( float * float ) (τ * τ ) <: (τ ’ * τ ’) 1 2 1 2 τ τ τ τ 1 <: ’1 … n <: ’n τ τ τ τ depth ( 1 * … * n) <: ( ’1 * … * ’n)

2 Width and Depth for Records Subtyping and Mutability

τ τ Similar rule for records {l 1 : 1,…,ln: n} Mutability destroys the ability to subtype Width considers any subset of labels since τ ref = {get:unit → τ, set: τ → unit} order of labels doesn’t matter. τ’ ref = {get:unit → τ’, set: τ’ → unit} Implementing this efficiently can be tricky Assume τ <: τ’ from that we conclude but doable unit → τ <: unit → τ’ and τ’ → unit <: τ → unit

Subtyping Defines Preorder/DAG Typechecking With Subtyping

Subtyping relation can form any DAG With explicit typing every expression has a unique type so we can use type synthesis

domesticatedmammal wild to compute the type of an expression Under implicit typing an expression may have many different types, which one feline canine should we choose? e.g. CalicoCat : mammal , cat tigerdog wolf CalicoCat : feline , and CalicoCat : cat

Which Type to Use? Which Type to Use?

Consider weight: mammal → float Consider weight: mammal → float countWiskers: feline → int countWiskers: feline → int

let val = CalicoCat let val c: mammal = CalicoCat in (weight c,countWiskers c) in (weight c, countWiskers c) end end

What type should we use for c? What type should we use for c?

3 Which Type to Use? Which Type to Use?

Consider weight: mammal → float Consider weight: mammal → float countWiskers: feline → int countWiskers: feline → int

let val c: feline = CalicoCat let val c: cat = CalicoCat in (weight c,countWiskers c) in (weight c,countWiskers c) end end

How do we know this is the “best” solution? Choose the most specific type.

Principal Types Subtyping Defines Preorder/DAG

Principal type is the “most specific” type. It is Q: What is the least element “principal type” the least type in a given pre-order defined for “mammal”?

by the subtype relation domesticatedmammal wild Lack of principal types makes type synthesis impossible with implicit subtyping unless programmer annotates code feline canine Not at as big a problem for explicit subtyping rules cat tigerdog wolf

Subtyping Defines Preorder/DAG Implementing Subtyping

A: “mammal” has no principal type in the For inclusive based semantics maybe hard subtyping relation defined below to implement or impose restrictions on representations of values domesticatedmammal wild Coercive based semantics give more freedom on choosing appropriate representation of values feline canine Can use “type-directed translation” to convert inclusive system to coercive cat tigerdog wolf system

4 Subtyping with Coercions Subtyping with Coercions (cont) τ τ v Define a new relation 1 <: 2  v τ → τ Where is a function of type ( 1 2)

Implementing Record Subtyping Approaches to Record Subtyping

Implementing subtyping on tuples is easy Represent record as a “hash-table” keyed by label since address index “does the right thing” name ((1, 2, 3) : (int * int * int)).2 Convert record to tuple when coercing create new tuple that represents different record with ((1, 2, 3) : (int * int)).2 appropriate fields Selecting the field label with records is more Two level approach represent record as “view” and challenging value. Dynamically coerce views. ({a=1,b=2,c=3} : {a:int,b:int,c:int}).c (Java interfaces are implemented this way, but you can statically compute all the views in Java) ({a=1,b=2,c=3} : {a:int,c:int}).c

By Name vs Structural Subtyping Summary

Harper adopts a structural view of subtyping. Coercive vs Inclusive Things are subtypes if they are some how Operational view of what subtyping means isomorphic. Implicit vs Explicit Java adopts a “by name” view. Things are How represents subtyping subtypes if they are structurally compatible and Systems can support all possible combinations the user declared them as subtypes. Need to think things through to avoid bugs Java approach leads to simpler type-checking and Tuples/records have both width and depth subtyping implementation but is arguably less modular Functions are contravariant in argument type than a pure structural approach References are invariant

5