Imperative Programming with Dependent Types Hongwei Xi University of Cincinnati 20 September 2018
Talk Overview Motivation Programming language Xanadu Conclusion Program error detection Compilation certification Proof-carrying code Programming language Xanadu Design decisions Dependent type system Programming examples Conclusion 20 September 2018
Some Advantages of Types Detecting program errors at compile-time Enabling compiler optimizations Facilitating program verification Using types to encode program properties Verifying the encoded properties through type-checking Serving as program documentation Unlike informal comments, types are formally verified and can thus be trusted 20 September 2018
Limitations of (Simple) Types Not general enough Many correct programs cannot be typed For instance, downcasts are widely used in Java Not specific enough Many interesting program properties cannot be captured For instance, types in Java cannot handle safe array access 20 September 2018
Narrowing the Gap NuPrl Coq Program Extraction Proof synthesis Dependent ML ML 20 September 2018
A Challenging Problem How can we prove the correctness of a (realistic) compiler? Verifying that the semantics of P is the same as the semantics of |P| for every program P But this simply seems too challenging (and is unlikely to be feasible) compilation | . | Source program P Target code |P| 20 September 2018
Compilation Certification Assume that P(P) holds, i.e., P has the property P Then there is likely some property |P| related to P such that |P|(|P|) holds A compiler can be designed to produce a certificate that asserts |P| does have the property |P| compilation | . | Source program P: P(P) holds Target code |P|: |P|(|P|) holds 20 September 2018
Proof-Carrying Code Unpacking Code Poof-Carrying Code Verifying Proof Executing Memory Safety Termination 20 September 2018
Proof Construction Building type derivations at source level with a practical type inference algorithm Translating such type derivations into proofs at target level compilation | . | Source program P Target code |P| Proof of P(P) Proof of |P|(|P|) proof translation 20 September 2018
Talk Overview Motivation Programming language Xanadu Conclusion Program error detection Compilation certification Proof-carrying code Programming language Xanadu Design decisions Dependent type system Programming examples Conclusion 20 September 2018
Xanadu: an Exotic Place In Xanadu did Kubla Khan A stately pleasure-dome decree … … -- Samuel Taylor Coleridge 20 September 2018
Xanadu: an “Exotic” Language Xanadu is an imperative programming language with C/Java-like syntax that supports a restricted form of dependent types The type of a variable in Xanadu may change during execution The programmer may need to provide dependent type annotations for type-checking purpose 20 September 2018
A Type for Arrays A polymorphic type for arrays record <‘a> array { size: int; data[]: ‘a } But this does not enforce that the integer stored in size is the size of the array to which data points size data 20 September 2018
A Dependent Type for Arrays A polymorphic type for arrays {n:nat} record <‘a> array(n) { size: int(n); data[n]: ‘a } 20 September 2018
Informal Comments /* the function should not be applied to a negative integer */ int factorial (x: int) { /* defensive programming */ if (x < 0) exit(1); if (x == 0) return 1; else return (x * factorial (x-1)); } Note: factorial(-1) is well-typed! 20 September 2018
Formalizing Comments {n:nat} int factorial (x: int(n)) { if (x == 0) return 1; else return (x * factorial (x-1)); } Note: factorial (-1) is now ill-typed and rejected! 20 September 2018
Informal Comments /* arrays a and b are of equal size */ float dotprod (float a[], float b[]) { int i; float sum = 0.0; if (a.size != b.size) exit(1); for (i = 0; i < a.size; i = i + 1) { sum = sum + a[i] * b[i]; } return sum; 20 September 2018
Formalizing Comments {n:nat} float dotprod (a: <float> array(n), b: <float> array(n)) { /* dotprod is assigned the following type: {n:nat}. (<float> array(n),<float> array(n)) -> float */ /* function body */ … … … } 20 September 2018
Some Design Decisions Practical type-checking Realistic programming features Conservative extension Pay-only-if-you-use policy 20 September 2018
Examples of Dependent Types int(i): singleton type containing the only integer equal to i, where a ranges over all integers <‘a> array(n): type for arrays of size n in which all elements are of type ‘a, where n ranges over all natural numbers 20 September 2018
Examples of Dependent Types int(i,j) is defined as [a:int | i < a < j] int(a), that is, the sum of all types int(a) for i < a < j int[i,j), int(i,j], int[i,j] are defined similarly nat is defined as [a:int | a >=0] int(a) 20 September 2018
Array Initialization in Xanadu {n:nat} unit init (vec: <int> array(n)) { var: int ind;; invariant: [i:int | i>=0] (ind: int(i)) for (ind=0; ind<vec.size; ind=ind+1){ vec.data[ind] = 0; } 20 September 2018
A Slight Variation {n:nat} unit init (vec: <int> array(n)) { var: int ind;; invariant: [i:int | i<=n] (ind: int(i)) for (ind=vec.size; ind>=0; ind=ind-1){ vec.data[ind] = 0; } 20 September 2018
Another Slight Variation {n:nat} unit init (vec: <int> array(n)) { var: nat ind;; for (ind=0; ind<vec.size; ind=ind+1){ vec.data[ind] = 0; } 20 September 2018
Binary Search in Xanadu {n:nat} int bsearch (key: int, vec: <int> array(n)) { var: int l, h, m, x;; l = 0; h = vec.size - 1; invariant: [i:int,j:int | 0<=i<=j+1<=n] (l:int(i),h:int(j)) while (l <= h) { m = (l + h) / 2; x = vec.data[m]; if (x < key) { l = m - 1; } else if (x > key) { h = m + 1; } else { return m; } } return –1; 20 September 2018
A Slight Variation {n:nat} int bsearch (key: int, vec: <int> array(n)) { var: l: int[0, n], h: int[-1, n); int m, x;; l = 0; h = vec.size - 1; while (l <= h) { m = (l + h) / 2; x = vec.data[m]; if (x < key) { l = m - 1; } else if (x > key) { h = m + 1; } else { return m; } } return –1; 20 September 2018
2-dimensional Arrays A polymorphic type for 2-dimensional arrays: {m:nat,n:nat} record <‘a>array2(m,n) { row: int(m); col: int(n); data[m][n]: ‘a } 20 September 2018
Sparse Arrays A polymorphic type for sparse arrays: {m:nat,n:nat} record <‘a> sparseArray(m,n) { row: int(m); col: int(n); data[m]: <int[0,n) * ‘a> list } 20 September 2018
Dependent Union Types A polymorphic type for lists: union <‘a> list with nat = { Nil(0); {n:nat} Cons(n+1) of ‘a * <‘a> list(n) } Nil: <‘a> list(0) Cons:{n:nat}.‘a * <‘a> list(n) -> <‘a> list(n+1) 20 September 2018
Dependent Union Types A polymorphic type for binary trees: union <‘a> tree with (nat,nat) = { E(0,0); {sl:nat,sr:nat,hl:nat,hr:nat} B(sl+sr+1,1+max(hl,hr)) of <‘a> tree(sl,hl) * ‘a * <‘a> tree(sr,hr) } The two indices represent size and height, respectively 20 September 2018
Type Judgment in Xanadu f1;D1;G |- e: (f2;D2;t) f: Context for index variables D: Context for variables with mutable types G: Context for variables with fixed types 20 September 2018
--------------------------- Typing an Assignment f1;D1;G |- e: (f2;D2;t) --------------------------- f1;D1;G |- x = e: (f2;D2[x->t];unit) 20 September 2018
Typing a Loop f1;D1 |- $f.D f1,f;D;G|- e1:(f2;D2;bool(i)) f2,i=1;D2;G |- e2:(f3;D3;unit) f3;D3 |- $f.D ---------------------------- f1;D1;G |-while(e1,e2):(f2,i=0;D2;unit) Note: $f.D is a loop invariant 20 September 2018
Reverse Append in Xanadu (‘a) {m: nat, n: nat} <‘a> list(m+n) revApp (xs: <‘a> list(m), ys: <‘a> list(n)) { var: ‘a x;; invariant: [m1: nat, n1: nat | m1+n1=m+n] (xs: <‘a> list(m1), ys: <‘a> list(n1)) while (true) { switch (xs) { case Nil: return ys; case Cons(x, xs): ys = Cons(x, ys); } } exit; /* can never be reached */ } 20 September 2018
A Generated Constraint The following integer constraint is generated when the revApp example is type-checked: m:nat,n:nat,m1:nat,n1:nat, m1+n1=m+n,a:nat,m1=a+1 |= a+(n1+1)=m+n 20 September 2018
Talk Overview Motivation Programming language Xanadu Conclusion Program error detection Compilation certification Proof-carrying code Programming language Xanadu Design decisions Dependent type system Programming examples Conclusion 20 September 2018
Current Status of Xanadu A prototype implementation of Xanadu in Objective Caml that performs two-phase type-checking, and generates assembly level code An interpreter for interpreting assembly level code A variety of examples (FFT, Heapsort, Quicksort, Gaussian elimination, etc.) at http://www.ececs.uc.edu/~hwxi/Xanadu/Xanadu.html 20 September 2018
Conclusion It is still largely an elusive goal in practice to verify the correctness of a program It is therefore important to identify those program properties that can be effectively verified for realistic programs 20 September 2018
Conclusion We have designed a type-theoretic approach to capturing some simple arithmetic reasoning in programming The preliminary studies indicate that this approach allows the programmer to capture many more properties in realistic programs while retaining practical type-checking 20 September 2018
Future Work Adding more programming features into Xanadu in particular, OO features Type-preserving compilation: constructing a compiler for Xanadu that can translate dependent types from source level into bytecode level Incorporating dependent types into (a subset of) Java and … 20 September 2018
Related Work Here is some related work Dependent types in practical programming (Xi & Pfenning) Cayenne (Augustsson) TALC Compiler (Morrisett et al at Cornell) Safe C compiler: Touchstone (Necula & Lee) TIL compiler (the Fox project at CMU) FLINT compiler (Shao et al at Yale) Secure Internet Programming (Appel, Felten et al at Princeton) 20 September 2018
End of the Talk Thank You! Questions? 20 September 2018