This is a study of the computing power of the subtyping machine behind Kennedy and Pierce’s nominal subtyping with variance. We depict the lattice of fragments of Kennedy and Pierce’s type system and characterize their computing power in terms of regular, context-free, deterministic, and non-deterministic tree languages. Based on the theory, we present Treetop—a generator of C#implementations of subtyping machines. The software artifact constitutes the first feasible (yet POC) fluent API generator to support context-free API protocols in a decidable type system fragment.
6. Subtyping
Subtyping with type parameters
Collection<b> x = new List<b>(); ✓
List<a> list_b = new List<b>(); ✗
list_b.add(new a()); ✗
5/21
7. Subtyping
Subtyping with type parameters
Collection<b> x = new List<b>(); ✓
List<a> list_b = new List<b>(); ✗
list_b.add(new a()); ✗
5/21
List<b> list_a = new List<a>(); ✗
b y = list_a.get(0); ✗
9. Variance
interface ReadOnlyList<out x> {
x get(int i);
}
Covariance
More derived type arguments
ReadOnlyList<a> x = new ReadOnlyList<b>(); ✓
a y = x.get(0); ✓
6/21
11. Variance
interface WriteOnlyList<in x> {
void add(x x);
}
Contravariance
Less derived type arguments
WriteOnlyList<b> x = new WriteOnlyList<a>(); ✓
x.add(new b()); ✓
7/21
12. Decidability of Subtyping
(Kennedy and Pierce 2007)
Abstract subtyping type system
Undecidable—reduced to PCP
Tractable type system fragments
Restricted subtyping semantics are decidable
How complex are these fragments?
8/21
13. Types Are Trees
A set of types is a set of trees
• Also called a tree language or a forest
• Defined by a tree grammar
a<b<c>, d>
a
b
c
d
9/21
14. Tree Grammars
Generalize “word” grammars for trees
Productions are tree/term rewrite rules
Class of tree grammars (regular, context-free, etc.)
Defined by a restriction on the form of productions
10/21
18. Results
class a<x> : b<a<b<x>>> {}
Expansively recursive inheritance
The expansion of types through inheritance is unlimited
12/21
a<c> → b<a<b<c>>>
19. Results
class a<x> : b<a<b<x>>> {}
Expansively recursive inheritance
The expansion of types through inheritance is unlimited
12/21
a<c> → b<a<b<c>>> → a<b<c>>
20. Results
class a<x> : b<a<b<x>>> {}
Expansively recursive inheritance
The expansion of types through inheritance is unlimited
12/21
a<c> → b<a<b<c>>> → a<b<c>> → b<a<b<b<c>>>>
21. Results
class a<x> : b<a<b<x>>> {}
Expansively recursive inheritance
The expansion of types through inheritance is unlimited
12/21
a<c> → b<a<b<c>>> → a<b<c>> → b<a<b<b<c>>>>
→ a<b<b<c>>>
22. Results
class a<x> : b<a<b<x>>> {}
Expansively recursive inheritance
The expansion of types through inheritance is unlimited
12/21
a<c> → b<a<b<c>>> → a<b<c>> → b<a<b<b<c>>>>
→ a<b<b<c>>> → … (a<c> → a<b*<c>>)
23. Results
Non-expansive subtyping is regular
Subtyping machines with non-expansive class tables
recognize regular forests
interface σ<+x> {}
interface v : σ<v> {}
13/21
24. Results
Example: Cons-lists of Peano numbers
Nat ::= z | s(Nat)
3 s(s(s(z)))
List ::= nil | cons(Nat, List)
[2,1,0] cons(s(s(z)),
cons(s(z),
cons(z,
nil)))
14/21
25. Results
Example: Cons-lists of Peano numbers
// Grammar terminals
interface z {} interface s<out x> {} interface nil {}
interface cons<out x1, out x2> {}
15/21
26. Results
Example: Cons-lists of Peano numbers
// Grammar terminals
interface z {} interface s<out x> {} interface nil {}
interface cons<out x1, out x2> {}
// Nat ::= z | s(Nat)
interface Nat : z, s<Nat> {}
// List ::= nil | cons(Nat, List)
interface List : nil, cons<Nat, List> {}
15/21
27. Results
Example: Cons-lists of Peano numbers
// Grammar terminals
interface z {} interface s<out x> {} interface nil {}
interface cons<out x1, out x2> {}
// Nat ::= z | s(Nat)
interface Nat : z, s<Nat> {}
// List ::= nil | cons(Nat, List)
interface List : nil, cons<Nat, List> {}
// List <: [2,1,0]
cons<s<s<z>>, cons<s<z>, cons<z, nil>>> t = (List) null; ✓
15/21
28. Results
Non-contravariant subtyping is context-free (GNF)
Subtyping machines without contravariance recognize
context-free forests with grammars in Greibach normal form
interface σ<+x> {}
interface v(x) : σ<τ> {}
16/21
29. Results
Example: Palindromes
// Grammar terminals
interface a<out x> {} interface b<out x> {} interface E {}
// v0(x) ::= a(v0(a(x))) | a(a(x)) | a(x) | b(v0(b(x))) | …
class v0<x> : a<v0<a<x>>>,a<a<x>>,a<x>,b<v0<b<x>>>,b<b<x>>,b<x> {}
// “abbabba” is a palindrome
a<b<b<a<b<b<a<E>>>>>>> w1 = new v0<E>(); ✓
// “abbabaa” is not a palindrome
a<b<b<a<b<a<a<E>>>>>>> w2 = new v0<E>(); ✗
17/21
30. Subtyping Metaprogramming
Some APIs have context-free usage protocols
“It is an error to call Restore() more times than
Save() was called.”
- Android’s Canvas API
Canvas ::= Save Canvas Restore Canvas
| Save Canvas
18/21
32. Treetop
• Input: A context-free grammar G describing a domain-specific
language or an API protocol
• Output: A C# fluent API encoding L(G) using a subtyping machine
var shape = Canvas.Draw().Save().Draw().
Restore().Restore().
Done<Canvas>(); ✗ // Subtyping constraint
20/21
33. In Conclusion
• There is a correspondence between nominal subtyping and
formal forests
• Subtyping machines formalize subtyping computations
• Subtyping metaprogramming?
• Context-free languages can be recognized at compile-time in a
decidable type system fragment
21/21