The document summarizes key features of the Pizza programming language and compiler, which extended Java with functional programming capabilities. The Pizza language added parametric polymorphism (generics), first-class functions, and algebraic datatypes to Java. The Pizza compiler translated Pizza code into Java bytecode. It supported features like pattern matching on algebraic datatypes through translation into Java classes with tag fields. The document provides examples and explanations of how each Pizza feature was implemented.
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Pizza compiler
1. The Pizza Compiler
The Pizza Compiler
extending Java in a functional way
Sander Mak
Centre for Software Technology, Universiteit Utrecht
October 19, 2006
Center for Software Technology Sander Mak
2. The Pizza Compiler > Introduction
Outline
Introduction
1
Features
2
Rough edges
3
Related work
4
Conclusion
5
Center for Software Technology Sander Mak
3. The Pizza Compiler > Introduction
About the Pizza project
Main Pizza contributors: Martin Odersky and Philip Wadler
Project started 1996 (Java 1.1 era)
Last version: 2002
So, why study an abandoned research project?
The ideas are still very interesting (they don’t age as fast as our
1
computers...)!
Better insight into design of Java 1.5
2
See how FP and OO can integrate
3
Center for Software Technology Sander Mak
4. The Pizza Compiler > Introduction
Characteristics
Pizza language
Language adds three novel features:
Parametric Polymorphism (generics)
1
First class functions
2
Algebraic datatypes
3
Pizza is a strict superset of Java
Language defined by translation into
Java
Pizza compiler
Compiler outputs bytecode directly
But, can output Java sources
(pre-processor)
No dependency chasing
Of course: written in Pizza!
Center for Software Technology Sander Mak
5. The Pizza Compiler > Introduction
Let’s move on to the features...
Ask questions if code is unclear
Center for Software Technology Sander Mak
6. The Pizza Compiler > Features > Parametric Polymorphism
Introducing Parameterized Types
Collections API (List, Hashtable, etc.) relies on generic
programming
Up to Java 1.4 simulated by implementing them with the top of
the type-hierarchy: Object
class Hashtable { .. public Object get(Object key) { .. } }
This leads to runtime type errors: programmer is responsible for
types in a collection consistent
Parameterized types solve this problem
class Hashtable<K,V> { .. public V get(K key) { .. } }
No runtime checks necessary anymore
Center for Software Technology Sander Mak
7. The Pizza Compiler > Features > Parametric Polymorphism
Introducing Parameterized Types
Type parameters can have bounds:
class Tree<A implements TreeNode> { .. }
class Maximum<A implements Comparable<A>> { .. }
Very similar to Haskell type-classes!
Primitive types (int, char) are allowed as instantiation for
type parameters
Omitting a bound implies the bound Object
Instantiating parameterized types:
List<int> = new List<int>();
Tree<TreeNodeImpl> = new Tree<TreeNodeImpl>();
Center for Software Technology Sander Mak
8. The Pizza Compiler > Features > Parametric Polymorphism
Two translation schemes
Homogeneous (Type Erasure)
Creates one Java implementation for each parameterized class
Replace type variables by their respective bounds
Parameterized array types are replaced with pizza.support.array
type
Heterogeneous
Creates specialised instances for each instantiation of type
parameter
Even at runtime specialisations can be generated, using reflection
Center for Software Technology Sander Mak
9. The Pizza Compiler > Features > Parametric Polymorphism
Translation scheme - Homogeneous (Type erasure)
Pizza source
class TranslateMe<A, B extends String> {
public A test(A a, B[] bs){
B b = bs[0];
return a; }
}
Translated Java source
class TranslateMe {
public Object test(Object s, pizza.support.array bs) {
String b = (String)bs.at(0);
return a;
}
}
Problem: how can primitive types be used as an object?
Center for Software Technology Sander Mak
10. The Pizza Compiler > Features > Parametric Polymorphism
Invariant/covariant subtyping
Is List<String> a subtype of List<Object>?
Center for Software Technology Sander Mak
11. The Pizza Compiler > Features > Parametric Polymorphism
Invariant/covariant subtyping
Is List<String> a subtype of List<Object>?
Consider:
class Loophole {
public static String loophole (Byte y) {
LinkedList<String> xs = new LinkedList<String>();
LinkedList<Object> ys = xs; // aliasing
ys.add(y);
return xs.iterator().next();
}
}
Center for Software Technology Sander Mak
12. The Pizza Compiler > Features > Parametric Polymorphism
Invariant/covariant subtyping
Is List<String> a subtype of List<Object>?
Consider:
class Loophole {
public static String loophole (Byte y) {
LinkedList<String> xs = new LinkedList<String>();
LinkedList<Object> ys = xs; // aliasing
ys.add(y);
return xs.iterator().next();
}
}
The aliasing of xs and ys will result in a compile time error, to
guarantee soundness.
Therefore, these types are not involved in a subtyping relation:
parameterized types have invariant subtyping.
Center for Software Technology Sander Mak
13. The Pizza Compiler > Features > Parametric Polymorphism
Invariant/covariant subtyping
But.. String[] is a subtype of Object[] (covariant)!
Consider:
class Loophole {
public static String loophole (Byte y) {
String[] xs = new String[1];
Object[] ys = xs; // aliasing
ys[0] = y;
return xs[0];
}
}
Center for Software Technology Sander Mak
14. The Pizza Compiler > Features > Parametric Polymorphism
Invariant/covariant subtyping
But.. String[] is a subtype of Object[] (covariant)!
Consider:
class Loophole {
public static String loophole (Byte y) {
String[] xs = new String[1];
Object[] ys = xs; // aliasing
ys[0] = y;
return xs[0];
}
}
The assignment ys[0] = x will give a runtime error.
This is possible because JVM tracks runtime types of arrays!
Center for Software Technology Sander Mak
15. The Pizza Compiler > Features > Algebraic Datatypes
Datatypes in Haskell
data List a = Nil | Cons a (List a)
We could emulate this using a parameterized class List<A>, but...
sum Nil =0
sum (Cons e es) = e + sum es
Elegant pattern matching is still not possible.
Center for Software Technology Sander Mak
16. The Pizza Compiler > Features > Algebraic Datatypes
Datatypes in Haskell
data List a = Nil | Cons a (List a)
We could emulate this using a parameterized class List<A>, but...
sum Nil =0
sum (Cons e es) = e + sum es
Elegant pattern matching is still not possible.
Observation
1 Objects and inheritance ease adding new constructors to types,
given that #functions is relatively fixed
Algebraic datatypes ease adding new functions over types using
2
matching, give that constructors are relatively fixed
Can we combine this?
Center for Software Technology Sander Mak
17. The Pizza Compiler > Features > Algebraic Datatypes
Sum using ADT and pattern matching
class List<A> {
case Nil;
case Cons(A head, List<A> tail);
}
Center for Software Technology Sander Mak
18. The Pizza Compiler > Features > Algebraic Datatypes
Sum using ADT and pattern matching
class List<A> {
case Nil;
case Cons(A head, List<A> tail);
}
We can now define sum:
public static int sum(List<int> l){
switch (l) {
case Nil :
return 0;
case Cons (int e, List<int> es) :
return (e + sum(es));
}
Center for Software Technology Sander Mak
19. The Pizza Compiler > Features > Algebraic Datatypes
Sum using ADT and pattern matching
class List<A> {
case Nil;
case Cons(A head, List<A> tail);
}
We can now define sum:
public static int sum(List<int> l){
switch (l) {
case Nil :
return 0;
case Cons (int e, List<int> es) :
return (e + sum(es));
}
Unfortunately the compiler didn’t agree...
Center for Software Technology Sander Mak
20. The Pizza Compiler > Features > Algebraic Datatypes
Sum using ADT and pattern matching
Compiler error
An exception has occurred in the compiler. (v1.0g)
Please file a bug report at Sourceforge.net
Thank you.
Exception in thread quot;mainquot; java.lang.StackOverflowError
Center for Software Technology Sander Mak
21. The Pizza Compiler > Features > Algebraic Datatypes
Sum using ADT and pattern matching
Compiler error
An exception has occurred in the compiler. (v1.0g)
Please file a bug report at Sourceforge.net
Thank you.
Exception in thread quot;mainquot; java.lang.StackOverflowError
After some experimentation:
Fix
public static Integer sum(List<Integer> l){
switch (l) {
case Nil :
return new Integer(0);
case Cons (Integer e, List<Integer> es):
return new Integer(e.intValue() + sum(es).intValue());
}
Center for Software Technology Sander Mak
22. The Pizza Compiler > Features > Algebraic Datatypes
Pattern matching
Wildcard pattern is allowed for unused variables
Nested pattern matching is supported
Overlapping patterns are detected, and not allowed
Pizza compiler AST is an Algebraic datatype
Enumeration types are within reach (as in Java 1.5):
class Color {
case Red;
case Blue;
String toString() {
switch (this) {
case Red: return “Red”;
case Blue: return “Blue”;
}
}
}
Center for Software Technology Sander Mak
23. The Pizza Compiler > Features > Algebraic Datatypes
Translation to Java
class List {
static final List Nil = new List(1);
public final int Listtag;
static List Cons(Object head, List tail) {
return (List)new Cons(head, tail);
}
List(int Listtag) {
super(); this.Listtag = Listtag;
}
static class Cons extends List {
Object head; List tail;
Cons(Object head, List tail) {
super(2); this.head = head;
this.tail = tail;
}
}
}
Center for Software Technology Sander Mak
24. The Pizza Compiler > Features > Algebraic Datatypes
Translation to Java
class List {
static final List Nil = new List(1);
public final int Listtag;
static List Cons(Object head, List tail) {
return (List)new Cons(head, tail);
}
List(int Listtag) {
super(); this.Listtag = Listtag;
}
static class Cons extends List {
Object head; List tail;
Cons(Object head, List tail) {
super(2); this.head = head;
this.tail = tail;
Constructing an instance of List<int> in Pizza
}
} List<int> nums = List.Cons(1,List.Cons(2,List.Nil));
}
Center for Software Technology Sander Mak
25. The Pizza Compiler > Features > First-class functions
Why pass functions?
Let’s examine a sorted set implementation
Current practice
class Set implements SortedSet {
public Set(Comparator c){..}
.. }
interface Comparator {
int compare(Object o1, Object o2); }
Extra class definition and implementation necessary to provide ordering
functionality...
Center for Software Technology Sander Mak
26. The Pizza Compiler > Features > First-class functions
Why pass functions?
Let’s examine a sorted set implementation
Current practice
class Set implements SortedSet {
public Set(Comparator c){..}
.. }
interface Comparator {
int compare(Object o1, Object o2); }
Extra class definition and implementation necessary to provide ordering
functionality...
What if...
class TreeSet {
public TreeSet((Object,Object) -> int compare)
{ .. order = compare(o1,o2); .. } .. }
Center for Software Technology Sander Mak
27. The Pizza Compiler > Features > First-class functions
Syntax
Pizza adds function types and values to Java
Function declaration (member or local)
(Object,Object) -> int compare =
fun (Object o1,Object o2) -> int {.. implementation ..};
Implementation may reference o1, o2, and everything in enclosing class
(not itself!)
Function declaration top-level
public int compare(Object o1, Object o2) {.. implementation ..};
Top-level functions can be passed around by using their name without
parentheses.
Comparator example is solvable using anonymous class instances.
But how powerful/scalable is this approach?
Center for Software Technology Sander Mak
28. The Pizza Compiler > Features > First-class functions
Let’s make a Pizza foldr!
public class Foldr {
static <D,E> D foldr((E,D) -> D f, D unit, List<E> l){
switch(l){
case Nil: return unit;
case Cons(E h, List<E> t): return f(h,foldr(f,unit,t));
}
}
Type of foldr in Haskell
foldr :: (a → b → b) → b → [a] → b
Center for Software Technology Sander Mak
29. The Pizza Compiler > Features > First-class functions
Let’s make a Pizza foldr!
public class Foldr {
static <D,E> D foldr((E,D) -> D f, D unit, List<E> l){
switch(l){
case Nil: return unit;
case Cons(E h, List<E> t): return f(h,foldr(f,unit,t));
}
}
static Integer add(Integer i1, Integer i2){
return new Integer(i1.intValue() + i2.intValue());
}
public static void main(String[] args){
(List<Integer>) -> int sum =
fun (List<Integer> l) -> int
{(foldr(add,new Integer(0),l))};
}
Center for Software Technology Sander Mak
}
30. The Pizza Compiler > Features > First-class functions
Does this first-class function feature transform Pizza/Java into
Haskell?
spacer
Well... not really:
No currying
No referential transparency
No lazy evaluation
Center for Software Technology Sander Mak
31. The Pizza Compiler > Features > First-class functions
Translation to Java
A class with First class
functions results in 2
translated classes
Most important task: ensure
scoped variables are available
spacer
spacer
Translated Functions class
spacer
contains a method for every
There are 3 cases to consider:
first-class function body
Local definition of a function
FunctionsClosures extends 1
pizza.support.Closure and has Passing of functions
2
an apply method for each Application of a function
3
signature
Center for Software Technology Sander Mak
32. The Pizza Compiler > Features > First-class functions
Translation to Java
Functions.pizza
1 class Functions {
2 public Functions(int a){
(int) -> int incr = fun (int i)->int {return i+a;};
3
4 int result = this.f(incr);
}
5
6 public int f((int) -> int incr){
7 return incr(2);
}
8
9}
Center for Software Technology Sander Mak
33. The Pizza Compiler > Features > First-class functions
Translation to Java
Functions.pizza
1 class Functions {
2 public Functions(int a){
(int) -> int incr = fun (int i)->int {return i+a;};
3
4 int result = this.f(incr);
}
5
6 public int f((int) -> int incr){
7 return incr(2);
}
8
9}
Case 1: Local definition (line 3)
pizza.support.Closure incr = new FunctionsClosures(this,
0, new Object[]{new Integer(a)});
Center for Software Technology Sander Mak
34. The Pizza Compiler > Features > First-class functions
Translation to Java
Functions.pizza
1 class Functions {
2 public Functions(int a){
(int) -> int incr = fun (int i)->int {return i+a;};
3
4 int result = this.f(incr);
}
5
6 public int f((int) -> int incr){
7 return incr(2);
}
8
9}
Case 1: Local definition (line 3)
int closureFunctions0(int i, Object[] freevars) {
int a = ((Number)freevars[0]).intValue();
return i+a;
}
Center for Software Technology Sander Mak
35. The Pizza Compiler > Features > First-class functions
Translation to Java
Functions.pizza
1 class Functions {
2 public Functions(int a){
(int) -> int incr = fun (int i)->int {return i+a;};
3
4 int result = this.f(incr);
}
5
6 public int f((int) -> int incr){
7 return incr(2);
}
8
9}
Case 2: Passing functions (line 4)
int result = this.f(incr);
Center for Software Technology Sander Mak
36. The Pizza Compiler > Features > First-class functions
Translation to Java
Functions.pizza
1 class Functions {
2 public Functions(int a){
(int) -> int incr = fun (int i)->int {return i+a;};
3
4 int result = this.f(incr);
}
5
6 public int f((int) -> int incr){
7 return incr(2);
}
8
9}
Case 3: Applying functions (line 7)
public int f(pizza.support.Closure incr) {
return ((Number)incr.apply(new Integer(2))).intValue();
}
Center for Software Technology Sander Mak
37. The Pizza Compiler > Rough edges
Language mismatches and other problems
There is a fixed maximum on the #arguments for first-class
functions (definition of Closure)
Access modifiers are not fine-grained enough for accurate
translation
Lots of typecasts are inserted to pass bytecode verification. Most
are not necessary because of Pizza’s typesystem
Generic array creation and generic instantiation are not possible
due to type erasure
’Strict superset’-claim is false: cannot use (new) keyword fun as
identifier
Center for Software Technology Sander Mak
38. The Pizza Compiler > Related work
Other approaches
GJ: Generic Java spin-off from Pizza
Only the parameterized types from Pizza
Some differences: only reference type parameters,
compatibility with non-generic classes, generic array
creation
Ended up in Java 1.5!
Scala language by Martin Odersky
Departs from notion of translation into the Java
language
Result: more freedom to implement new features
Runs on JVM
C++ Templates superficially similar to parameterized types
More like macros: each instantiation results in a new
class
Templates are not type-checked (only their
instances)
Center for Software Technology Sander Mak
39. The Pizza Compiler > Conclusion > Opinion
Quality of error messages
A measure of compiler quality can be the quality of its errors:
Failure of bound-inference for generic types leads to good,
understandable feedback
Omitting a case in a switch leads to a vague error message about
a missing return statement
There is an (undocumented) fixed maximum on the number of
arguments for a first class function. Violating this gives a long,
vague error message
I would say that Pizza is usable, but not in production environments.
Center for Software Technology Sander Mak
40. The Pizza Compiler > Conclusion > Opinion
Quality in general
Papers on Pizza are very well written
A very thorough description of the Pizza typesystem shows that
the project is not mere hacking of cool features
Implementation is not robust, not unusable either
I would say that Pizza is a very good example of a research project
that had significant impact (through Generic Java → Java 1.5)
Center for Software Technology Sander Mak
41. The Pizza Compiler > Conclusion > The End
I hope this overview encourages you to find new ways to enhance
existing ideas! spacer
spacer
Odersky and Wadler:
’We are not short on innovations, but we need more ways to translate
innovation in to practice’
spacer
Try it yourself @ pizzacompiler.sourceforge.net
Center for Software Technology Sander Mak