33
1 Unifying Object-Oriented Programming with Typed Functional Programming Hongwei Xi Boston University

1 Unifying Object-Oriented Programming with Typed Functional Programming Hongwei Xi Boston University

  • View
    228

  • Download
    0

Embed Size (px)

Citation preview

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

10

A Type for Objects

We can now use the following type for objects:

OBJ = {’a}. ’a MSG -> ’a

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

33

End of the Talk Thank You!

Questions?