Whiteoak: Introducing Structural Typing into Java
Customizing Non-Customizable Code
Itay Maman, Yossi Gil
Technion
IBM Leadership Seminar PLE'08, 25-Jun-2008
2/17
Java – A Graph Library
public interface Node { public int degree(); public Node getNeighbor(int i);}
public class Graph { private class NodeImpl implements Node { ... } public static Node parse(String s) { ... }}
3/17
Our Mission
Introduce a new method Signature: boolean isNeighborOf(Node n)
b
Semantics: true if n is a neighbor of this
Subclassing will not work Graph.parse() creates NodeImpl objects No customization means
Luckily, this is not a problem for Whiteoak ...
4/17
Whiteoakpublic struct MyNode = Node + {
public boolean isNeighborOf(Node n) { for(int i = 0; i < degree(); ++i) if(getNeighbor(i) == n) return true; return false; }}
Node n = Graph.parse("....");MyNode m = n;m.isNeighborOf(...);
assert m == n; // ... as expected in Java
5/17
Evaluation: Whiteoak Solution
8 lines of code Method definition: 6 lines Overhead: 2 lines
No need for hooks in the library
Q: #Lines of code in the Java solution?
6/17
Highlights Structural types
In addition to Java's interfaces, classes
Similar to interfaces Cannot be created Can only used as types: variables, return types, etc.
7/17
Highlights (cont.)
Unlike interfaces, Structural types support:
Fields, constructors Behave just like virtual methods
Methods can be non-abstract Provide default implementations
Structural subtyping
8/17
Structural Vs. Nominal Java: nominal subtyping
A subtype must name its supertypes E.g.: class A implements B ...
Whiteoak:
Classes, interfaces – nominal subtyping Structural types - structural subtyping
A is structural-subtype of B<=>
Every abstract member of B has a matching member in A
9/17
X is a Subtype of Spublic struct S { public int value; public constructor(int n); public int add(int n);
public void subtract(int n) { return add(n); }}
public class X { public int value; public X(int n) { value = n; } public int add(int n) { return value + n; }}
10/17
Y is not a Subtype of Spublic struct S { public int value; public constructor(int n); public int add(int n);
public void subtract(int n) { return add(n); }}
public class Y { private int value; public Y(int n, double d) { value = n; } public int add_x(int n) { return value + n; }}
11/17
Runtime Semantics
X x = new X(5);
S s = x; // s – static type: S, // dynamic type: X
s.add(3) // Effectively: x.add()
s.value // Effectively: x.value
s.constructor(10) // Effectively: new X(10)
s.subtract(9) // Invokes S.subtract()
12/17
Implementation Guidelines
Avoid executable blow-up
Avoid whole-world analysis Not even whole-package analysis
Maintain identities of objects Assignment => equality of references
No special JVM
13/17
Invisible Wrappers // Original program:
struct S { void f(); } class C { void f() { } }
void someMethod() { S s = new C(); ... s.f(); }
// Compiled program:
interface S { void f(); }
void someMethod() { Object s = new C(); ... // C dynamic type of s← // create an StoC adapter // invoke f() on the adapter }
class S_C implements S { private C c; S_C(Object o) { c = (C) o; }
public void f() { c.f(); }}
14/17
Performance Caching System
Real-life programs JESS, JAVAC (SpecJVM98)
Other benchmarks do not use interfaces Replaced 'interface' with 'struct' Bottom line: No observable slowdown
15/17
A Java Solution Decorator pattern
MyNode 1-1 Mapping
HashMap<Node,MyNode> Memory explosion
WeakHashMap<Node,WeakReference<MyNode>> Concurrency
Scalability
DecoratedNode<T> Different identities, different classes
No solution Node.equals() is probably useless
16/17
43 lines of Code public abstract class DecoratedNode<T extends Node> implements Node {
protected abstract T create(Map<Node, WeakReference<T>> m, Node n); private Map<Node, WeakReference<T>> map; private Node inner;
protected DecoratedNode(Map<Node, WeakReference<T>> map, Node n) { inner = n; this.map = map; }
public int degree() { return inner.degree(); }
public T getNeighbor(int i) { Node n = inner.getNeighbor(i); synchronized(map) { WeakReference<T> r = map.get(n); T t = r == null ? null : r.get(); if(t == null) { t = create(map, n); map.put(n, new WeakReference<T>(t)); } return t; } }}
public class MyNode extends DecoratedNode<MyNode> { public MyNode(Map<Node, WeakReference<MyNode>> map, Node n) { super(map, n); }
protected MyNode create(Map<Node, WeakReference<MyNode>> m, Node n) { return new MyNode(m, n); }
public boolean isNeighborOf(Node n) { for(int i = 0; i < degree(); ++i) if(getNeighbor(i) == n) return true; return false; } }}
17/17
- The End-
http://whiteoak.sourceforge.net