Upload
lintaro-ina
View
372
Download
0
Embed Size (px)
Citation preview
Gradual Typing for Generics
Lintaro Ina and Atsushi Igarashi
Kyoto University
2011-10-26 @ OOPSLA 2011
Lintaro Ina Gradual Typing for Generics 1
Dynamic vs. Static Typing
•+ flexible
•- unexpectedrun-time errors
•+ reliable
•- tedious to write typeannotations
Lintaro Ina Gradual Typing for Generics 2
Gradual Typing [’06 Siek and Taha]
◮ combines benefits of both sides
◮ Dynamic and static types are both allowed◮ Statically typed part never goes wrong
prototype product release
◮ allows evolutionary development
◮ from flexible scripts◮ to reliable programs
Lintaro Ina Gradual Typing for Generics 3
Recipe for Gradual Typing [1/3]
1 Adding dynamic type dyn
◮ Allow potentially safe code
Lintaro Ina Gradual Typing for Generics 4
Recipe for Gradual Typing [1/3]
1 Adding dynamic type dyn
◮ Allow potentially safe code
dyn x = ...;
x.anyMethod();
String y = x;
y.length();
Lintaro Ina Gradual Typing for Generics 4
Recipe for Gradual Typing [1/3]
1 Adding dynamic type dyn
◮ Allow potentially safe code
dyn x = ...;
x.anyMethod();
String y = x;
y.length();
Lintaro Ina Gradual Typing for Generics 4
Recipe for Gradual Typing [2/3]
2 Translation to an intermediate language
◮ Explicit run-time checks in dyn-parts◮ dyn-free parts do not change
dyn x = ...;
x.anyMethod();
String y = x;
y.length();
Lintaro Ina Gradual Typing for Generics 5
Recipe for Gradual Typing [2/3]
2 Translation to an intermediate language
◮ Explicit run-time checks in dyn-parts◮ dyn-free parts do not change
dyn x = ...;
x.anyMethod();
String y = x;
y.length();
dyn x = ...;
invoke(x, anyMethod);
String y = $String% x;
y.length();
Lintaro Ina Gradual Typing for Generics 5
Recipe for Gradual Typing [3/3]
3 Proof of type safety
◮ Only run-time checks may fail◮ The translation preserves typeability
Lintaro Ina Gradual Typing for Generics 6
Recipe for Gradual Typing
1 Adding dynamic type dyn
◮ Allow potentially safe code
2 Translation to an intermediate language
◮ Explicit run-time checks in dyn-parts◮ dyn-free parts do not change
3 Proof of type safety
◮ Only run-time checks may fail◮ The translation preserves typeability
Lintaro Ina Gradual Typing for Generics 7
Our Goal
A gradual type system for Java
Theory
◮ A type system
◮ Proofs of properties
Implementation
◮ A type checker
◮ Byte-code generation for the current JVM
Lintaro Ina Gradual Typing for Generics 8
Our Goal
A gradual type system for Java
Theory
◮ A type system
◮ Proofs of properties
Implementation
◮ A type checker
◮ Byte-code generation for the current JVM
Lintaro Ina Gradual Typing for Generics 8
Issues
◮ Class-based nominal type system
◮ cf. structural type system [’07 Siek and Taha]
◮ Generics
◮ What can we do with List<dyn>?
◮ Matching with the current Java architectures
◮ Each class compiles to a single class file◮ Behavior of statically typed parts
Lintaro Ina Gradual Typing for Generics 9
What We Do and Don’t
Do
◮ Gradual type system for nominal subtyping
◮ Fine-grained integration with generics
◮ Flexible compatibility relation
◮ Ensuring type safety
◮ Bounded dynamic types◮ Run-time checks for parametric types
Don’t
◮ Blame tracking
Lintaro Ina Gradual Typing for Generics 10
What We Do and Don’t
Do
◮ Gradual type system for nominal subtyping
◮ Fine-grained integration with generics
◮ Flexible compatibility relation
◮ Ensuring type safety
◮ Bounded dynamic types◮ Run-time checks for parametric types
Don’t
◮ Blame tracking
Lintaro Ina Gradual Typing for Generics 10
Generics and Dynamic Types
◮ List<dyn> can be used as List<whatever>
◮ You can’t do this in C# 4.0 [’10 Bierman, et al.]
class List<X> { X head; List<X> tail }
List<dyn> ls = ...;
ls.head.anyMethod();
List<String> sls = ls;
Lintaro Ina Gradual Typing for Generics 11
Generics and Dynamic Types
◮ List<dyn> can be used as List<whatever>
◮ You can’t do this in C# 4.0 [’10 Bierman, et al.]
class List<X> { X head; List<X> tail }
List<dyn> ls = ...;
ls.head.anyMethod();
List<String> sls = ls;
◮ How does type checking go?
Lintaro Ina Gradual Typing for Generics 11
Static Compatibility [1/2]
Static Compatibility S . T
S x = ...;
T y = x;
// Is this allowed by the compiler?
◮ Checks whether type S is compatible to type T
◮ Used instead of normal subtype relation <:
Lintaro Ina Gradual Typing for Generics 12
Static Compatibility [2/2]
Static Compatibility S . T
◮ Includes <:
◮ Co- and contra-variant◮ List<String>. List<dyn>◮ List<dyn> . List<String>
are both OK
Lintaro Ina Gradual Typing for Generics 13
Static Compatibility [2/2]
Static Compatibility S . T
◮ Includes <:
◮ Co- and contra-variant◮ List<String>. List<dyn>◮ List<dyn> . List<String>
are both OK
/* the compiler should not reject this */
List<dyn> ls1 = new List<String>(...);
// List<String>. List<dyn>
List<String> ls2 = ls1;
// List<dyn> . List<String>
Lintaro Ina Gradual Typing for Generics 13
Bounded Dynamic Types [1/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
Lintaro Ina Gradual Typing for Generics 14
Bounded Dynamic Types [1/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
Lintaro Ina Gradual Typing for Generics 14
Bounded Dynamic Types [1/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
new NCell<dyn>(new Integer(...)).x.bar();
new NCell<dyn>(new Integer(...)).foo();
new NCell<dyn>("abc").foo();
Lintaro Ina Gradual Typing for Generics 14
Bounded Dynamic Types [1/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
new NCell<dyn>(new Integer(...)).x.bar();
new NCell<dyn>(new Integer(...)).foo();
new NCell<dyn>("abc").foo();
Lintaro Ina Gradual Typing for Generics 14
Bounded Dynamic Types [1/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
new NCell<dyn>(new Integer(...)).x.bar();
new NCell<dyn>(new Integer(...)).foo();
new NCell<dyn>("abc").foo();
Lintaro Ina Gradual Typing for Generics 14
Bounded Dynamic Types [1/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
new NCell<dyn>(new Integer(...)).x.bar();
new NCell<dyn>(new Integer(...)).foo();
new NCell<dyn>("abc").foo(); // reject
Lintaro Ina Gradual Typing for Generics 14
Bounded Dynamic Types [1/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
new NCell<dyn>(new Integer(...)).x.bar();
new NCell<dyn>(new Integer(...)).foo();
new NCell<dyn>("abc").foo(); // reject
How?
Lintaro Ina Gradual Typing for Generics 14
Bounded Dynamic Types [2/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
// constructor type
NCell<X>:X→ NCell<X>
NCell<dyn>:dyn→ NCell<dyn>
Lintaro Ina Gradual Typing for Generics 15
Bounded Dynamic Types [2/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
// constructor type
NCell<X>:X→ NCell<X>
NCell<dyn>:dyn<Number>→ NCell<dyn<Number>>
Lintaro Ina Gradual Typing for Generics 15
Bounded Dynamic Types [2/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
// constructor type
NCell<X>:X→ NCell<X>
NCell<dyn>:dyn<Number>→ NCell<dyn<Number>>
Bounded Dynamic Type dyn<N>
◮ T . dyn<N> if T <: N◮ T 6. dyn<N> if T 6<: N
Lintaro Ina Gradual Typing for Generics 15
Bounded Dynamic Types [2/2]
class NCell<X extends Number> {
/* in a single NCell.class */
X x; void foo() { this.x.intValue(); } }
// constructor type
NCell<X>:X→ NCell<X>
NCell<dyn>:dyn<Number>→ NCell<dyn<Number>>
Bounded Dynamic Type dyn<N>
◮ T . dyn<N> if T <: N◮ T 6. dyn<N> if T 6<: N
String 6. dyn<Number> (∵ String 6<: Number)
Lintaro Ina Gradual Typing for Generics 15
Run-time checks
List<dyn> ls = new List<Integer>(...);
ls.head.anyMethod();
List<String> sls = ls;
Lintaro Ina Gradual Typing for Generics 16
Run-time checks
◮ Assume List<dyn> as a citizen of thedynamically typed world
List<dyn> ls = new List<Integer>(...);
ls.head.anyMethod();
List<String> sls = ls;
Lintaro Ina Gradual Typing for Generics 16
Run-time checks
◮ Assume List<dyn> as a citizen of thedynamically typed world
List<dyn> ls = $List<dyn>% new List...;
invoke(ls.head, anyMethod);
List<String> sls = $List<String>% ls;
Lintaro Ina Gradual Typing for Generics 16
Run-time checks
◮ Assume List<dyn> as a citizen of thedynamically typed world
List<dyn> ls = $List<dyn>% new List...;
invoke(ls.head, anyMethod);
List<String> sls = $List<String>% ls;
◮ When does $T% e succeed?
Lintaro Ina Gradual Typing for Generics 16
Run-time Compatibility [1/2]
Run-time Compatibility S :≺ T
$T% new S(...);
// Does this succeed at run time?
◮ Checks whether a value of S is compatible to T
◮ Used instead of normal subtype relation <:
Lintaro Ina Gradual Typing for Generics 17
Run-time Compatibility [2/2]
Run-time Compatibility S :≺ T
◮ Includes <:◮ Co-variant but not contra-variant
◮ List<String> :≺ List<dyn>◮ List<dyn> 6 :≺ List<String>
Lintaro Ina Gradual Typing for Generics 18
Run-time Compatibility [2/2]
Run-time Compatibility S :≺ T
◮ Includes <:◮ Co-variant but not contra-variant
◮ List<String> :≺ List<dyn>◮ List<dyn> 6 :≺ List<String>
List<dyn> ls1 = new List<dyn>(...);
ls1.head = new Integer(1);
List<String> ls2 = ls1;
ls2.head.length();
Lintaro Ina Gradual Typing for Generics 18
Run-time Compatibility [2/2]
Run-time Compatibility S :≺ T
◮ Includes <:◮ Co-variant but not contra-variant
◮ List<String> :≺ List<dyn>◮ List<dyn> 6 :≺ List<String>
List<dyn> ls1 = new List<dyn>(...);
ls1.head = new Integer(1);
List<String> ls2 = ls1;
ls2.head.length(); /* should not fail
because it’s statically typed */Lintaro Ina Gradual Typing for Generics 18
Run-time Compatibility [2/2]
Run-time Compatibility S :≺ T
◮ Includes <:◮ Co-variant but not contra-variant
◮ List<String> :≺ List<dyn>◮ List<dyn> 6 :≺ List<String>
List<dyn> ls1 = new List<dyn>(...);
ls1.head = new Integer(1);
List<String> ls2 = ls1; /* run-time error
List<dyn> 6:≺ List<String> */
ls2.head.length(); // this does not execute
Lintaro Ina Gradual Typing for Generics 18
Formalization
◮ Extend Featherweight GJ (FGJ) with dyn
◮ Give a translation to an intermediate language
◮ . and :≺ instead of normal subtyping <:
Surface language Intermediate languageFGJ + dyn FGJ + dyn + run-time checkscompatibility . compatibility :≺
typing (typing)reduction
Lintaro Ina Gradual Typing for Generics 19
Compatibility Relations
Auxiliary Relation S ≺ T
◮ In S, dyns in T are replaced with non-dyns
∆ ⊢ T ≺ T∆ ⊢ S ≺ T
∆ ⊢ C<S> ≺ C<T>
∆ ⊢ T <: S ∆ ⊢ S ≺ N
∆ ⊢ T ≺ dyn<N>
Definitions
◮ Static compatibility S . Tdef
= S ≻ ∃U <: ∃V ≺ T
◮ Run-time compatibility S :≺ Tdef
= S <: ∃U ≺ T
Lintaro Ina Gradual Typing for Generics 20
Properties
Weak Type Safety in the Intermediate LanguageAn execution of a program of type T
1 results in a value of type S ( :≺ T), or
2 results in a failure of a run-time check, or
3 does not stop
Translation from the Surface to the IntermediateA well-typed program can translate and
◮ typeability is preserved
◮ statically typed parts do not change
Lintaro Ina Gradual Typing for Generics 21
Conclusions
◮ Gradual typing for class-based languages
◮ Fine-grained integration with generics
◮ Static and run-time compatibility◮ Bounded dynamic types
◮ Formalization
◮ FGJ + dyn + run-time checks◮ Type safety and translation theorem
Lintaro Ina Gradual Typing for Generics 22
Future Work
◮ Decidability of . and :≺
:≺ decidable?. at least semidecidable?
◮ Full compiler with a large scale evaluation
◮ Integration with method overloading,wildcards, etc.
◮ Blame tracking instead of run-timecompatibility checks
Lintaro Ina Gradual Typing for Generics 23