Implementing a Language with Flow-Sensitive and Structural Subtyping on the JVM David J. Pearce and...

19
Implementing a Language with Flow-Sensitive and Structural Subtyping on the JVM David J. Pearce and James Noble Victoria University of Wellington

Transcript of Implementing a Language with Flow-Sensitive and Structural Subtyping on the JVM David J. Pearce and...

Implementing a Language with Flow-Sensitive and Structural

Subtyping on the JVM

David J. Pearce and James NobleVictoria University of Wellington

void buildLabelMap(List<Bytecode> bytecodes) {

HashMap<String,Integer> labels = new HashMap<String,Integer>();

int idx = 0

for(Bytecode b : bytecodes) {

if(b instanceof Bytecode.Label) {

Bytecode.Label lab = (Bytecode.Label) b;

labels.put(lab.name, idx);

}

idx = idx + 1;

} }

def buildLabelMap(bytecodes):

labels = {}

idx = 0

for b in bytecodes:

if type(b) == “Label”:

labels[b.name] = idx

idx = idx + 1

Python:

Java:

The Whiley Language

• Design Goals:

– Look and feel of a dynamically typed language

– But, still provide static type checking

– Simple programming model

– Amenable to program verification

void buildLabelMap([Bytecode] bytecodes):

labels = {}

idx = 0

for b in bytecodes:

if b ~= Label:

labels[b.name] = idx

idx = idx + 1

Whiley:

The Whiley Language

• Design Goals:

– Look and feel of a dynamically typed language

– But, still provide static type checking

– Simple programming model

– Amenable to program verification

void buildLabelMap([Bytecode] bytecodes):

labels = {}

idx = 0

for b in bytecodes:

if b ~= Label:

labels[b.name] = idx

idx = idx + 1

Whiley:

The Whiley Language

• Design Goals:

– Look and feel of a dynamically typed language

– But, still provide static type checking

– Simple programming model

– Amenable to program verification

void buildLabelMap([Bytecode] bytecodes):

labels = {}

idx = 0

for b in bytecodes:

if b ~= Label:

labels[b.name] = idx

idx = idx + 1

Whiley:

Union Types

• Union types have many uses– Such as neatly handling null references– Or, combining different kinds (i.e. unions of structs)

null|int indexOf(string str, char c):

[string] split(string str, char c):

idx = indexOf(str,c)

if idx ~= int:

below = str[0..idx]

above = str[idx..]

return [below,above]

else:

return [str]

Union Types

• Union types have many uses– Such as neatly handling null references– Or, combining different kinds (i.e. unions of structs)

null|int indexOf(string str, char c):

[string] split(string str, char c):

idx = indexOf(str,c)

if idx ~= int:

below = str[0..idx]

above = str[idx..]

return [below,above]

else:

return [str]

Structural Subtyping

• Defined types are not nominal– i.e. LinkedList is just a name that “expands”

define LinkedList as null | {int dat, LinkedList nxt}

define NonEmptyList as {int dat, LinkedList nxt}

int sum(LinkedList l):

if !(l ~= NonEmptyList):

return 0

else:

return l.dat + sum(l.nxt)

void main([string] args):

l={dat: 1, nxt: null}

l={dat: 2, nxt: l}

out->println(sum(l))

Structural Subtyping

• Defined types are not nominal– i.e. LinkedList is just a name that “expands”

define LinkedList as null | {int dat, LinkedList nxt}

define NonEmptyList as {int dat, LinkedList nxt}

int sum(LinkedList l):

if l ~= NonEmptyList:

return 0

else:

return l.dat + sum(l.nxt)

void main([string] args):

l={dat: 1, nxt: null} // l->{int dat, null nxt}

l={dat: 2, nxt: l} // l->{int dat, {int dat, null nxt} nxt}}

out->println(sum(l))

Implementation

Numbers

• Unbounded Integers & Rationals

– How to implement efficiently on JVM?

1)BigInteger and BigRational

2)SmallInt, BigInt and BigRational [Clojure & Erjang]

3)int[]

• Adding 100,000 random (small) ints

– BigInteger(11ms), SmallInt/BigInt (1ms), int[] (1ms)

real weird(real x, [int] map):

if x ~= int:

// convert x to int

x = map[x]

// convert x back to real

return x

Records

• HashMap implementation:– Map field names to objects– Record access are HashMap lookups

• Array implementation– Fields allocated to array elements– Faster lookup times– Problem with width subtyping of records

define Point as {int x, int y}

define Point3D as {int x, int y, int z}

int weird(Point p):

return p.x + p.y

int alsoWierd(Point3D p3d):

return weird(p3d)

“x”

12

“y”

3

Runtime Type Tests

• Type testing without names is difficult!

– Elements may require recursive type test

void f([real] xs):

if xs ~= [int]:

else:

void f(List xs):

for(Object _x : xs) {

Number x = (Number) x;

if(!x.isInteger()) {

goto elseLab;

} }

return

elseLab:

return

Type Testing Records

• Type testing records == checking for fields

– Can do better than brute-force “check all” approach

– Test smallest set of “uniquely identifying” fields

define Point as {int x, int y}

define Point3D as {int x, int y, int z}

int weird(Point p):

if p ~= Point3D:

else:

Testing Recursive Types

• Recursive types are also awkward

– Must recursively check every node– Potentially expensive – like for lists

define LinkedList as {int data, LinkedList y}

define WeirdList as {null|int data, WeirdList y}

int weird(WeirdList p):

if p ~= LinedList:

else:

JVM not fully flow-sensitive!!!

• JVM uses flow-sensitive typing algorithm

– Doesn’t account for instanceof tests

– Have to insert casts to keep verifier happy

define nstring as null|string

int length(nstring ns):

if ns ~= string:

return |ns|

else:

return 0

0: aload_0

1: dup

2: instanceof java/util/List

3: ifeq …

4: checkcast java/util/List

5: invokeinterface size()I

6: …

Cloning

• Data types have value semantics:

– i.e. lists are not references (as in Java)

– E.g. must “clone” lists on assignment

– This is inefficient – want to reduce number of clones

– E.g. 28125 clones in Chess benchmark (508LOC)

void System::main([string] args):

xs = [1,2,3]

ys = xs // clone required

ys[0] = 2

out->println(str(xs))

out->println(str(ys))

Conclusion

• Design Goals:

– Look and feel of a dynamically typed language

– But, still provide static type checking

• Implementation on JVM– Efficient representation of integers / rationals– Efficient representation of records– Efficient type testing … ?– Efficient value semantics … ?

http://whiley.org