May 1, 2003May 1, 2003 1 Imperative Programming with Dependent Types Hongwei Xi Boston University.
1 Unifying Object-Oriented Programming with Typed Functional Programming Hongwei Xi Boston...
-
date post
21-Dec-2015 -
Category
Documents
-
view
227 -
download
0
Transcript of 1 Unifying Object-Oriented Programming with Typed Functional Programming Hongwei Xi Boston...
1
Unifying Object-Oriented Programming with Typed Functional Programming
Hongwei XiBoston University
2
Talk Overview
Motivation for this work Some difficult issues in designing a
type system to support object-oriented programming
An approach to implementing objects through the use of guarded recursive datatype constructors
3
Motivation
Support object-oriented programming in a typed functional programming language
Take a CLOS-like approach to object-oriented programming Following Smalltalk, objects are not
treated as records in this approach
4
Difficulties in Typing Objects All existing approaches to typing objects
that we know contain some major deficiencies The programmer needs to program around
the deficiencies Run-time type checks are employed to
overcome the deficiencies Some deficiencies exist even in a bare
minimum core that supports object-oriented programming
5
A Problem with Return Typesclass ObjClass {
…virtual copy: ObjClass;
…}
class StringClass inherits ObjClass {…
copy = … …
}
6
A Problem with Binary Methods
class eqClass {virtual equal (other: eqClass): bool;…}
class aEqClass inherits eqClass { … }class bEqClass inherits eqClass { … }
7
A Puzzling Exampleclass objClass {
…virtual copy: objClass;
…}
class int1Class inherits objClass{…copy = ... ;…}
class int2Class inherits int1Class {
…}
8
Types for Messages
We use MSG as a type constructor for constructing types for messages
Given a type , the type MSG is for messages that require objects to return values of type after receiving them.
9
Message Constructors
We can use some syntax to declare message constructors:
MSGgetfst: (int) MSGMSGsetfst: int -> (unit) MSGMSGgetsnd: (int) MSGMSGsetsnd: int -> (unit) MSG
11
Object Constructor for IntPairClass
fun newIntPair (x:int, y:int): OBJ = let val xref = ref x val yref = ref y fun dispatch (MSGgetfst) = !xref | dispatch (MSGsetfst x’) = (xref := x’) | dispatch (MSGgetsnd) = !yref | dispatch (MSGsetsnd y’) = (yref := y’) | dispatch msg = raise UnknownMessage
in dispatch end
12
A Serious Problem
As in Smalltalk, there is so far no type-level differentiation between objects For instance, let anIntPair be an object
constructed by calling newIntPair. If we send a message MSGfoo to anIntPair, then an exception is to be thrown at run-time.
We would really like to have a type system that can stop this at compile-time
13
Class Tags We treat classes as tags. A message type is now of the form:
MSG(C), where C is a class tag. For instance,
MSGgetfst: (int)MSG(IntPairClass)MSGsetfst: int -> (unit)MSG(IntPairClass)
The type of an object is of the form: OBJ(C) = {’a}. ’a MSG(C) -> ’a For instance,
newIntPair: int int -> OBJ(IntPairClass)
14
Parameterized Class Tags
There is an immediate need for class tags parameterized over types:
MSGgetfst: {’a,’b}. (’a) MSG((’a,’b)PairClass) MSGsetfst: {’a,’b}. ’a -> (unit) MSG((’a,’b)PairClass) MSGgetsnd: {’a,’b}. (’b) MSG((’a,’b)PairClass)MSGsetsnd: {’a,’b}. ’b -> (unit) MSG((’a,’b)PairClass)
15
Object Constructor for PairClass
fun newPair (x, y) = letval xref = ref xval yref = ref yfun dispatch (MSGgetfst) = !xref | dispatch (MSGsetfst x’) = (xref := x’) | dispatch (MSGgetsnd) = !yref | dispatch (MSGsetsnd y’) = (yref := y’)
in dispatch endwithtype {’a,’b}. ’a ’b ->
OBJ((’a,’b)PairClass)
16
Subclasses
We define a relation on class tags{’a,’b}. (’a,’b)ColoredPairClass < (’a,’b)PairClass
The type of a message constructor is now of the following form:{’a1,…,’an,c <= C} 1 -> (2) MSG(c)
For instance,MSGgetfst: {’a,’b,c<= (’a,’b)PairClass}. (’a) MSG(c)MSGsetfst: {’a,’b,c<= (’a,’b)PairClass}. ’a -> (unit) MSG(c)
17
Contravariant Use of SelfType
class EqClass {MSGeq: SelfType -> bool;MSGneq: SelfType -> bool;
}
MSGeq: {c <= EqClass}. OBJ(c) -> (bool) MSG(c)MSGneq: {c <= EqClass}. OBJ(c) -> (bool)
MSG(c)
18
Covariant Use of SelfType
class objClass {… …MSGclone: SelfType… …
}
MSGclone: {c <= ObjClass}. (OBJ(c)) MSG(c)
19
Inheritance We explain how inheritance can be
implemented.
class Int1Class inherits ObjClass { MSGget1: int; MSGset1: int -> unit; MSGdouble: unit => self(MSGset1(2 self(MSGget1)));}
The declaration essentially does the following:Int1Class <= ObjClassMSGget1: {c <= Int1Class} (int) MSG(c)MSGset1: {c <= Int1Class} int -> (unit) MSG(c)MSGdouble: {c <= Int1Class} (unit) MSG(c)
20
Super Functions
Each class is associated with a “super” function
Given a class C, the super function associated with C has the type:
{c <= C}. OBJ(c) -> OBJ(c)
21
Examples of Super Functions fun superObj (self) = let
fun dispatch (MSGclone) = self | dispatch msg = raise UnknownMessagein dispatch endwithtype {c <= ObjClass} OBJ(c) -> OBJ(c)
fun superInt1 (self) = let fun dispatch (MSGdouble) = self(MSGset1(2 self(MSGget1))) | dispatch msg = superObj self msgin dispatch endwithtype {c <= Int1Class} OBJ(c) -> OBJ(c)
22
Object Constructor for Int1Class
We implement an object constructor for the Int1Class as follows:
fun newInt1 (x)= let val xref = ref x fun dispatch (MSGget1) = !xref | dispatch (MSGset1 x’) = (xref := x’) | dispatch (MSGclone) = newInt1 (!xref) | dispatch msg = superInt1 dispatch msgin dispatch endwithtype int -> OBJ(Int1Class)
23
A Class Declaration
class Int2Class inherits Int1Class { MSGget2: int;MSGset2: int -> unit;
}The declaration essentially does the
following:Int2Class <= Int1ClassMSGget2: {c <= Int2Class} (int) MSG(c)MSGset2: {c <= Int2Class} int -> (unit)
MSG(c)
24
Super Function and Constructor for Int2Class
fun superInt2 (self) = letfun dispatch msg = superInt1 self msg
withtype {c <= Int2Class} OBJ(c) -> OBJ(c)
fun newInt2 (x1, x2) = letval x1ref = ref x1val x2ref = ref x2fun dispatch (MSGget1) = !x1ref | dispatch (MSGset1 x) = (x1ref := x) | dispatch (MSGget2) = !x2ref | dispatch (MSGset2 x) = (x2ref := x) | dispatch msg = superInt2 dispatch msg
in dispatch endwithtype int * int -> OBJ(Int2Class)
25
Some Interesting Questions Let O2 be an object created by calling
newInt2 What happens if we send the message MSGdouble to
O2: O2(MSGdouble) ? No method is implemented for MSGdouble in newInt2 No method is implemented for MSGdouble in superInt2 A method lookup finds it through superInt1
What happens if we sent the message MSGclone to O2: O2(MSGclone) ?
No method is implemented for MSGclone in newInt2 No method is implemented for MSGclone in superInt2 No method is implemented for MSGclone in superInt1 A method finds it through superObj
26
Subtyping Given a class tag C,
OBJECT(C) = [c <= C] OBJ(c) E.g.,
OBJ((OBJECT(eqClass),OBJECT(eqClass))pairClass)
is the type for pairs whose both components support equality test
27
Type Representation
typecon (type) TY = (int) TYint| {’a,’b}. (’a * ’b) TYtup of ’a TY * ’b TY| {’a,’b}. (’a -> ’b) TYfun of ’a TY * ’b TY| {’a}. (’a TY) TYtyp of ’a TY
TYint: (int) TYTYtup: {’a,’b}. ’a TY * ’b TY -> (’a * ’b) TYTYfun: {’a,’b}. ’a TY * ’b TY -> (’a -> ’b) TYTYtyp: {’a}. ’a TY -> (’a TY) TY
28
An Example: val2string
fun val2string pf x =case pf of TYint => int2string x| TYtup (pf1, pf2) => “(” ^ val2string pf1 (fst x) ^ “,” ^ val2string pf2 (snd x) ^ “)”| TYfun _ => “[a function]”| TYtyp _ => “[a type]”
withtype {’a}. ’a TY -> ’a -> string
29
H.O.A.S. Trees
typecon (type) HOAS = {’a}. (’a) HOASlift of ’a| {’a}. (’a) HOASif of bool HOAS * ’a HOAS * ’a HOAS| {’a,’b}. (’a * ’b) HOAStup of ’a HOAS * ’b HOAS| {’a,’b}. (’a -> ’b) HOASlam of ’a HOAS -> ’b HOAS| {’a}. (’a) HOASfix of ’a HOAS -> ’a HOAS
HOASlift: {’a}. ’a -> ’a HOASHOASif: {’a}. bool HOAS * ’a HOAS * ’a HOAS -> ’a HOASHOAStup: {’a,’b}. ’a HOAS * ’b HOAS -> (’a * ’b) HOASHOASlam: {’a,’b}. (’a HOAS -> ’b HOAS) -> (’a -> ’b) HOASHOASfix: {’a}. (’a HOAS -> ’a HOAS) -> ’a HOAS
30
Type-Preserving Evaluation
fun eval (HOASlift v) = v| eval (HOASif (b, e1, e2)) = if eval (b) then eval (e1) else eval (e2)| eval (HOAStup (e1, e2)) = (eval (e1), eval (e2))| eval (HOASlam (f)) = fn x => eval (f (HOASlift x))| eval (HOASfix f) = eval (f (HOASfix f))
withtype {’a}. ’a HOAS -> ’a
31
F.O.A.S. treestypecon (type,type) FOAS =
| {’a,’g}. (’a,’g) FOASlift of ’a| {’a,’g}. (’a,’a*’g) FOASone| {’a,’b,’g}. (’a,’b*’g) FOASshift of (’a,’g) FOAS| {’a,’b,’g}. (’a -> ’b,’g) FOASlam of (’b,’a*’g) FOAS| …
FOASlift: {’a,’g}. ’a -> (’a,’g) FOASFOASone: {’a,’g}. (’a,’a*’g) FOASFOASshift: {’a, ’b,’g}. (’a,’g) FOAS -> (’a,’b*’g) FOASFOASlam: {’a,’b,’g}. (’b,’a * ’g) FOAS -> (’a -> ’b,’g) FOAS…
32
Type-Preserving Evaluation
fun eval (FOASlift v) env = v| eval FOASone (v, env) = v| eval (FOASshift e) (_, env) = eval e env| eval (FOASlam e) env = fn x => eval e (x, env)| …
withtype {’a}. (’a,’g) FOAS -> ’g -> ’a
fun evaluate (e) = eval e ()withtype {’a}. (’a,unit) FOAS -> ’a