Verifying a hash table and its iterators in higher-order separation logic
François Pottier
CPP 2017
Paris, January 16, 2017
We want verified software...
Therefore, we need
VERIFIED
LIBRARIES.
The Vocal project is building a verified library of basic data structures and algorithms.
I
The code is in OCaml.
I
Verification can be done in higher-order separation logic :
I
Charguéraud’s CFML imports a view of the code into Coq ;
I
reasoning is carried out in Coq.
In this talk, I focus on one module : a hash table implementation.
Why verify a hash table implementation ?
I
a simple and useful data structure Why talk about it today ?
I
dynamically allocated ; mutable
I
equipped with two iteration mechanisms : fold, cascade
The data structure
First-order operations
Iteration via fold
Iteration via cascades
Conclusion
OCaml interface
An excerpt of HashTable.mli.
m o d u l e M a k e ( K : H a s h e d T y p e ) : s i g t y p e key = K . t
t y p e ’ a t (* C r e a t i o n . *)
v a l c r e a t e : int - > ’ a t v a l c o p y : ’ a t - > ’ a t (* I n s e r t i o n a n d r e m o v a l . *)
v a l add : ’ a t - > key - > ’ a - > u n i t v a l r e m o v e : ’ a t - > key - > u n i t (* L o o k u p . *)
v a l f i n d : ’ a t - > key - > ’ a o p t i o n v a l p o p u l a t i o n : ’ a t - > int
(* I t e r a t i o n . *)
v a l f o l d : ( key - > ’ a - > ’ b - > ’ b ) - >
’ a t - > ’ b - > ’ b v a l c a s c a d e : ’ a t - > ( key * ’ a ) c a s c a d e (* . . . m o r e o p e r a t i o n s , n o t s h o w n . *) e n d
OCaml interface
An excerpt of HashTable.mli.
m o d u l e M a k e ( K : H a s h e d T y p e ) : s i g t y p e key = K . t
t y p e ’ a t (* C r e a t i o n . *)
v a l c r e a t e : int - > ’ a t v a l c o p y : ’ a t - > ’ a t (* I n s e r t i o n a n d r e m o v a l . *)
v a l add : ’ a t - > key - > ’ a - > u n i t v a l r e m o v e : ’ a t - > key - > u n i t (* L o o k u p . *)
v a l f i n d : ’ a t - > key - > ’ a o p t i o n v a l p o p u l a t i o n : ’ a t - > int
(* I t e r a t i o n . *)
v a l f o l d : ( key - > ’ a - > ’ b - > ’ b ) - >
’ a t - > ’ b - > ’ b v a l c a s c a d e : ’ a t - > ( key * ’ a ) c a s c a d e (* . . . m o r e o p e r a t i o n s , n o t s h o w n . *) e n d
First-order operations
OCaml interface
An excerpt of HashTable.mli.
m o d u l e M a k e ( K : H a s h e d T y p e ) : s i g t y p e key = K . t
t y p e ’ a t (* C r e a t i o n . *)
v a l c r e a t e : int - > ’ a t v a l c o p y : ’ a t - > ’ a t (* I n s e r t i o n a n d r e m o v a l . *)
v a l add : ’ a t - > key - > ’ a - > u n i t v a l r e m o v e : ’ a t - > key - > u n i t (* L o o k u p . *)
v a l f i n d : ’ a t - > key - > ’ a o p t i o n v a l p o p u l a t i o n : ’ a t - > int
(* I t e r a t i o n . *)
v a l f o l d : ( key - > ’ a - > ’ b - > ’ b ) - >
’ a t - > ’ b - > ’ b v a l c a s c a d e : ’ a t - > ( key * ’ a ) c a s c a d e (* . . . m o r e o p e r a t i o n s , n o t s h o w n . *) e n d
Iteration
(producer in control)
OCaml interface
An excerpt of HashTable.mli.
m o d u l e M a k e ( K : H a s h e d T y p e ) : s i g t y p e key = K . t
t y p e ’ a t (* C r e a t i o n . *)
v a l c r e a t e : int - > ’ a t v a l c o p y : ’ a t - > ’ a t (* I n s e r t i o n a n d r e m o v a l . *)
v a l add : ’ a t - > key - > ’ a - > u n i t v a l r e m o v e : ’ a t - > key - > u n i t (* L o o k u p . *)
v a l f i n d : ’ a t - > key - > ’ a o p t i o n v a l p o p u l a t i o n : ’ a t - > int
(* I t e r a t i o n . *)
v a l f o l d : ( key - > ’ a - > ’ b - > ’ b ) - >
’ a t - > ’ b - > ’ b v a l c a s c a d e : ’ a t - > ( key * ’ a ) c a s c a d e (* . . . m o r e o p e r a t i o n s , n o t s h o w n . *) e n d
Iteration
(consumer in control)
OCaml implementation
An excerpt of HashTable.ml.
m o d u l e M a k e ( K : H a s h e d T y p e ) = s t r u c t (* T y p e d e f i n i t i o n s . *)
t y p e key = K . t t y p e ’ a b u c k e t =
V o i d
| M o r e of key * ’ a * ’ a b u c k e t t y p e ’ a t a b l e = {
m u t a b l e d a t a : ’ a b u c k e t a r r a y ; m u t a b l e p o p u : int ;
i n i t : int ; }
t y p e ’ a t = ’ a t a b l e
(* O p e r a t i o n s : s e e f o l l o w i n g s l i d e s . . . *) e n d
OCaml implementation
An excerpt of HashTable.ml.
m o d u l e M a k e ( K : H a s h e d T y p e ) = s t r u c t (* T y p e d e f i n i t i o n s . *)
t y p e key = K . t t y p e ’ a b u c k e t =
V o i d
| M o r e of key * ’ a * ’ a b u c k e t t y p e ’ a t a b l e = {
m u t a b l e d a t a : ’ a b u c k e t a r r a y ; m u t a b l e p o p u : int ;
i n i t : int ; }
t y p e ’ a t = ’ a t a b l e
(* O p e r a t i o n s : s e e f o l l o w i n g s l i d e s . . . *) e n d
A hash table is a record...
OCaml implementation
An excerpt of HashTable.ml.
m o d u l e M a k e ( K : H a s h e d T y p e ) = s t r u c t (* T y p e d e f i n i t i o n s . *)
t y p e key = K . t t y p e ’ a b u c k e t =
V o i d
| M o r e of key * ’ a * ’ a b u c k e t t y p e ’ a t a b l e = {
m u t a b l e d a t a : ’ a b u c k e t a r r a y ; m u t a b l e p o p u : int ;
i n i t : int ; }
t y p e ’ a t = ’ a t a b l e
(* O p e r a t i o n s : s e e f o l l o w i n g s l i d e s . . . *) e n d
...whose data field is an
array of buckets...
OCaml implementation
An excerpt of HashTable.ml.
m o d u l e M a k e ( K : H a s h e d T y p e ) = s t r u c t (* T y p e d e f i n i t i o n s . *)
t y p e key = K . t t y p e ’ a b u c k e t =
V o i d
| M o r e of key * ’ a * ’ a b u c k e t t y p e ’ a t a b l e = {
m u t a b l e d a t a : ’ a b u c k e t a r r a y ; m u t a b l e p o p u : int ;
i n i t : int ; }
t y p e ’ a t = ’ a t a b l e
(* O p e r a t i o n s : s e e f o l l o w i n g s l i d e s . . . *) e n d
...where a bucket is a list
of key-value pairs.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
We use s to demand / guarantee that certain operations are read-only.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
A table represents a finite map of keys to (lists of) values.
We use s to demand / guarantee that certain operations are read-only.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
This SL predicate asserts
“the table at address h encodes the dictionary M”.
We use s to demand / guarantee that certain operations are read-only.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
This one names s the current concrete state
of the table.
We use s to demand / guarantee that certain operations are read-only.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
There must be a record at address h...
We use s to demand / guarantee that certain operations are read-only.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
...whose data field contains a pointer d...
We use s to demand / guarantee that certain operations are read-only.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
...to an array.
We use s to demand / guarantee that certain operations are read-only.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
The content of memory is related to M.
We use s to demand / guarantee that certain operations are read-only.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
The address and content of the array are exposed
under the name s.
We use s to demand / guarantee that certain operations are read-only.
Separation logic invariant (in Coq)
An excerpt of HashTable_proof.v.
I m p l i c i t T y p e M : key - > l i s t A . D e f i n i t i o n h ˜ > TableInState M s :=
H e x i s t s d pop i n i t data , h ˜ > ‘{
d a t a := d ; p o p u := pop ; i n i t := i n i t } \*
d ˜ > Array data \*
\[ t a b l e _ i n v M i n i t d a t a ] \*
\[ p o p u l a t i o n M = pop ] \*
\[ s = ( d , d a t a ) ].
D e f i n i t i o n h ˜ > Table M :=
H e x i s t s s , h ˜ > TableInState M s.
We hide s when we do not care about it.
We use s to demand / guarantee that certain operations are read-only.
The data structure
First-order operations
Iteration via fold
Iteration via cascades
Conclusion
Specifying a first-order operation : insertion
The effect of add h k x is to add the key-value pair (k, x) to the dictionary.
This is stated as a Hoare triple :
T h e o r e m a d d _ s p e c : f o r a l l M h k x , app MK . add [ h k x ]
PRE ( h ˜ > Table M)
P O S T ( fun _ = > H e x i s t s M ’ , h ˜ > Table M ’ \*
\[ M ’ = add M k x ] \*
\[ l e a n M - > M k = nil - > l e a n M ’ ]).
Specifying a first-order operation : insertion
The effect of add h k x is to add the key-value pair (k, x) to the dictionary.
This is stated as a Hoare triple :
T h e o r e m a d d _ s p e c : f o r a l l M h k x , app MK . add [ h k x ]
PRE ( h ˜ > Table M)
P O S T ( fun _ = > H e x i s t s M ’ , h ˜ > Table M ’ \*
\[ M ’ = add M k x ] \*
\[ l e a n M - > M k = nil - > l e a n M ’ ]).
The function call add h k x...
Specifying a first-order operation : insertion
The effect of add h k x is to add the key-value pair (k, x) to the dictionary.
This is stated as a Hoare triple :
T h e o r e m a d d _ s p e c : f o r a l l M h k x , app MK . add [ h k x ]
PRE ( h ˜ > Table M)
P O S T ( fun _ = > H e x i s t s M ’ , h ˜ > Table M ’ \*
\[ M ’ = add M k x ] \*
\[ l e a n M - > M k = nil - > l e a n M ’ ]).
...requires a valid table...
Specifying a first-order operation : insertion
The effect of add h k x is to add the key-value pair (k, x) to the dictionary.
This is stated as a Hoare triple :
T h e o r e m a d d _ s p e c : f o r a l l M h k x , app MK . add [ h k x ]
PRE ( h ˜ > Table M)
P O S T ( fun _ = > H e x i s t s M ’ , h ˜ > Table M ’ \*
\[ M ’ = add M k x ] \*
\[ l e a n M - > M k = nil - > l e a n M ’ ]).
...and produces a valid table...
Specifying a first-order operation : insertion
The effect of add h k x is to add the key-value pair (k, x) to the dictionary.
This is stated as a Hoare triple :
T h e o r e m a d d _ s p e c : f o r a l l M h k x , app MK . add [ h k x ]
PRE ( h ˜ > Table M)
P O S T ( fun _ = > H e x i s t s M ’ , h ˜ > Table M ’ \*
\[ M ’ = add M k x ] \*
\[ l e a n M - > M k = nil - > l e a n M ’ ]).
...representing a dictionary
with one more key-value pair.
The data structure
First-order operations
Iteration via fold
Iteration via cascades
Conclusion
Fold – for hash tables
l e t r e c f o l d _ a u x f b a c c u = m a t c h b w i t h
| V o i d - >
a c c u
| M o r e ( k , x , b ) - >
l e t a c c u = f k x a c c u in f o l d _ a u x f b a c c u
l e t f o l d f h a c c u = l e t d a t a = h . d a t a in l e t s t a t e = ref a c c u in
f o r i = 0 to A r r a y . l e n g t h d a t a - 1 do s t a t e := f o l d _ a u x f d a t a .( i ) ! s t a t e d o n e;
! s t a t e
Writing a specification for a fold raises some questions :
I
in what order does the consumer receive the key-value pairs ?
I
is the consumer allowed to access the table for reading ? for writing ?
Fold – for hash tables
l e t r e c f o l d _ a u x f b a c c u = m a t c h b w i t h
| V o i d - >
a c c u
| M o r e ( k , x , b ) - >
l e t a c c u = f k x a c c u in f o l d _ a u x f b a c c u
l e t f o l d f h a c c u = l e t d a t a = h . d a t a in l e t s t a t e = ref a c c u in
f o r i = 0 to A r r a y . l e n g t h d a t a - 1 do s t a t e := f o l d _ a u x f d a t a .( i ) ! s t a t e d o n e;
! s t a t e
A loop over the data array...
Writing a specification for a fold raises some questions :
I
in what order does the consumer receive the key-value pairs ?
I
is the consumer allowed to access the table for reading ? for writing ?
Fold – for hash tables
l e t r e c f o l d _ a u x f b a c c u = m a t c h b w i t h
| V o i d - >
a c c u
| M o r e ( k , x , b ) - >
l e t a c c u = f k x a c c u in f o l d _ a u x f b a c c u
l e t f o l d f h a c c u = l e t d a t a = h . d a t a in l e t s t a t e = ref a c c u in
f o r i = 0 to A r r a y . l e n g t h d a t a - 1 do s t a t e := f o l d _ a u x f d a t a .( i ) ! s t a t e d o n e;
! s t a t e
...a loop over a linked list...
Writing a specification for a fold raises some questions :
I
in what order does the consumer receive the key-value pairs ?
I
is the consumer allowed to access the table for reading ? for writing ?
Fold – for hash tables
l e t r e c f o l d _ a u x f b a c c u = m a t c h b w i t h
| V o i d - >
a c c u
| M o r e ( k , x , b ) - >
l e t a c c u = f k x a c c u in f o l d _ a u x f b a c c u
l e t f o l d f h a c c u = l e t d a t a = h . d a t a in l e t s t a t e = ref a c c u in
f o r i = 0 to A r r a y . l e n g t h d a t a - 1 do s t a t e := f o l d _ a u x f d a t a .( i ) ! s t a t e d o n e;
! s t a t e
...a call to the consumer.
Writing a specification for a fold raises some questions :
I
in what order does the consumer receive the key-value pairs ?
I
is the consumer allowed to access the table for reading ? for writing ?
Fold – for hash tables
l e t r e c f o l d _ a u x f b a c c u = m a t c h b w i t h
| V o i d - >
a c c u
| M o r e ( k , x , b ) - >
l e t a c c u = f k x a c c u in f o l d _ a u x f b a c c u
l e t f o l d f h a c c u = l e t d a t a = h . d a t a in l e t s t a t e = ref a c c u in
f o r i = 0 to A r r a y . l e n g t h d a t a - 1 do s t a t e := f o l d _ a u x f d a t a .( i ) ! s t a t e d o n e;
! s t a t e
Writing a specification for a fold raises some questions :
I
in what order does the consumer receive the key-value pairs ?
I
is the consumer allowed to access the table for reading ? for writing ?
Specifying an iteration order – in general
Really a matter of specifying which orders the consumer may observe.
The events that can be observed by a consumer are :
I
the production of one element ;
I
the end of the sequence (this event occurs at most once, and occurs last).
An observation can be defined as a sequence of events.
A set of observations can be described by two predicates (Filliâtre and Pereira) :
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p .
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
The spec is parameterized
over permitted and complete.
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
The consumer may assume every partial sequence she
observes is permitted.
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
After observing termination,
the consumer may deduce
the sequence is complete.
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
The spec is parameterized
over a loop invariant I.
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
The consumer
must preserve I.
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
The whole iteration is then
guaranteed to preserve I.
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
The spec is parameterized
over SL predicates S and S’.
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
The producer requires S
access to the collection.
Specifying fold – in general
This is a higher-order specification : an implication between Hoare triples.
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . V a r i a b l e I : l i s t A - > B - > h p r o p .
V a r i a b l e s S S ’ : C - > h p r o p . D e f i n i t i o n F o l d := f o r a l l f c ,
( f o r a l l x xs accu , p e r m i t t e d ( xs & x ) - >
c a l l f x a c c u
PRE ( S ’ c \* I xs a c c u )
P O S T ( fun a c c u = > S ’ c \* I ( xs & x ) a c c u ) ) - >
f o r a l l accu ,
app f o l d [ f c a c c u ]
PRE ( S c \* I nil a c c u ) P O S T ( fun a c c u = > H e x i s t s xs ,
S c \* I xs a c c u \*
\[ c o m p l e t e xs ]).
The producer gets S’ access,
which may be weaker.
Specifying an iteration order – for hash tables
For hash tables, we give concrete definitions of permitted and complete :
D e f i n i t i o n p e r m i t t e d kxs :=
e x i s t s M ’ , r e m o v a l M kxs M ’.
D e f i n i t i o n c o m p l e t e kxs :=
r e m o v a l M kxs e m p t y .
where removal M kxs M’ means that from M one may remove the key-value-pair sequence kxs to obtain M’.
This specification is semi-deterministic :
I
two key-value pairs for different keys may be observed in any order ;
I
two key-value pairs for the same key must be observed most-recent-value-first.
Specifying fold – for hash tables
The specification of fold for hash tables is an instance of the general spec :
T h e o r e m f o l d _ s p e c _ r o : f o r a l l M s B I , F o l d MK . f o l d
(* C a l l i n g c o n v e n t i o n : *) ( fun f kx ( a c c u : B ) = >
app f [( fst kx ) ( snd kx ) a c c u ]) (* P e r m i t t e d / c o m p l e t e s e q u e n c e s : *) ( p e r m i t t e d M ) ( c o m p l e t e M ) I
(* f o l d r e q u i r e s & p r e s e r v e s t h i s : *) ( fun h = > h ˜ > TableInState M s)
(* f r e c e i v e s a n d m u s t p r e s e r v e t h i s : *) ( fun h = > h ˜ > TableInState M s ).
This spec allows read-only access to the table during iteration,
and guarantees that iteration itself is a read-only operation.
Specifying fold – for hash tables
The specification of fold for hash tables is an instance of the general spec :
T h e o r e m f o l d _ s p e c _ r o : f o r a l l M s B I , F o l d MK . f o l d
(* C a l l i n g c o n v e n t i o n : *) ( fun f kx ( a c c u : B ) = >
app f [( fst kx ) ( snd kx ) a c c u ]) (* P e r m i t t e d / c o m p l e t e s e q u e n c e s : *) ( p e r m i t t e d M ) ( c o m p l e t e M ) I
(* f o l d r e q u i r e s & p r e s e r v e s t h i s : *) ( fun h = > h ˜ > TableInState M s)
(* f r e c e i v e s a n d m u s t p r e s e r v e t h i s : *) ( fun h = > h ˜ > TableInState M s ).
The predicates permitted and complete for hash tables.
This spec allows read-only access to the table during iteration,
and guarantees that iteration itself is a read-only operation.
Specifying fold – for hash tables
The specification of fold for hash tables is an instance of the general spec :
T h e o r e m f o l d _ s p e c _ r o : f o r a l l M s B I , F o l d MK . f o l d
(* C a l l i n g c o n v e n t i o n : *) ( fun f kx ( a c c u : B ) = >
app f [( fst kx ) ( snd kx ) a c c u ]) (* P e r m i t t e d / c o m p l e t e s e q u e n c e s : *) ( p e r m i t t e d M ) ( c o m p l e t e M ) I
(* f o l d r e q u i r e s & p r e s e r v e s t h i s : *) ( fun h = > h ˜ > TableInState M s)
(* f r e c e i v e s a n d m u s t p r e s e r v e t h i s : *) ( fun h = > h ˜ > TableInState M s ).
fold guarantees that the table is not modified.
This spec allows read-only access to the table during iteration,
and guarantees that iteration itself is a read-only operation.
Specifying fold – for hash tables
The specification of fold for hash tables is an instance of the general spec :
T h e o r e m f o l d _ s p e c _ r o : f o r a l l M s B I , F o l d MK . f o l d
(* C a l l i n g c o n v e n t i o n : *) ( fun f kx ( a c c u : B ) = >
app f [( fst kx ) ( snd kx ) a c c u ]) (* P e r m i t t e d / c o m p l e t e s e q u e n c e s : *) ( p e r m i t t e d M ) ( c o m p l e t e M ) I
(* f o l d r e q u i r e s & p r e s e r v e s t h i s : *) ( fun h = > h ˜ > TableInState M s)
(* f r e c e i v e s a n d m u s t p r e s e r v e t h i s : *) ( fun h = > h ˜ > TableInState M s ).
The consumer cannot modify the table.
This spec allows read-only access to the table during iteration,
and guarantees that iteration itself is a read-only operation.
Specifying fold – for hash tables
If access to the table during iteration is not needed, a simpler spec can be given :
T h e o r e m f o l d _ s p e c :f o r a l l M B I , F o l d MK . f o l d
( fun f kx ( a c c u : B ) = >
app f [( fst kx ) ( snd kx ) a c c u ]) ( p e r m i t t e d M ) ( c o m p l e t e M ) I
(* f o l d r e q u i r e s & p r e s e r v e s t h i s : *) ( fun h = > h ˜ > Table M)
(* f c a n n o t a c c e s s t h e t a b l e : *) ( fun h = > \ [ ] ) .
Specifying fold – for hash tables
If access to the table during iteration is not needed, a simpler spec can be given :
T h e o r e m f o l d _ s p e c :f o r a l l M B I , F o l d MK . f o l d
( fun f kx ( a c c u : B ) = >
app f [( fst kx ) ( snd kx ) a c c u ]) ( p e r m i t t e d M ) ( c o m p l e t e M ) I
(* f o l d r e q u i r e s & p r e s e r v e s t h i s : *) ( fun h = > h ˜ > Table M)
(* f c a n n o t a c c e s s t h e t a b l e : *) ( fun h = > \ [ ] ) .
fold does not guarantee that
the table is unchanged.
Specifying fold – for hash tables
If access to the table during iteration is not needed, a simpler spec can be given :
T h e o r e m f o l d _ s p e c :f o r a l l M B I , F o l d MK . f o l d
( fun f kx ( a c c u : B ) = >
app f [( fst kx ) ( snd kx ) a c c u ]) ( p e r m i t t e d M ) ( c o m p l e t e M ) I
(* f o l d r e q u i r e s & p r e s e r v e s t h i s : *) ( fun h = > h ˜ > Table M)
(* f c a n n o t a c c e s s t h e t a b l e : *) ( fun h = > \ [ ] ) .
The consumer gets no
access to the table.
The data structure
First-order operations
Iteration via fold
Iteration via cascades
Conclusion
Iterators
An iterator is an on-demand producer of a sequence of elements.
Iterators
What should be the type of an iterator ?
p u b l i c i n t e r f a c e
I t e r a t o r < E > {
E n e x t ()
t h r o w sN o S u c h E l e m e n t E x c e p t i o n ;
b o o l e a nh a s N e x t ();
}
This interface :
I
requires the iterator to be mutable ;
I
is more complex than strictly necessary.
Iterators
What should be the type of an iterator ?
p u b l i c i n t e r f a c e
I t e r a t o r < E > {
E n e x t ()
t h r o w sN o S u c h E l e m e n t E x c e p t i o n ;
b o o l e a nh a s N e x t ();
}
This interface :
I
requires the iterator to be mutable ;
I
is more complex than strictly necessary.
Iterators
What should be the type of an iterator ?
p u b l i c i n t e r f a c e
I t e r a t o r < E > {
E n e x t ()
t h r o w sN o S u c h E l e m e n t E x c e p t i o n ;
b o o l e a nh a s N e x t ();
}
NOT GREAT
This interface :
I
requires the iterator to be mutable ;
I
is more complex than strictly necessary.
Cascades
A cascade, or delayed list, is perhaps the simplest possible form of iterator.
t y p e ’ a c a s c a d e = u n i t - > ’ a h e a d a n d ’ a h e a d =
| Nil
| C o n s of ’ a * ’ a c a s c a d e
This definition offers an abstract, consumer-oriented view. It does not reveal :
I
whether a cascade has mutable internal state, or is pure ;
I
whether elements are stored in memory, or computed on demand ;
I
whether elements are re-computed when re-demanded, or memoized.
Cascades
A cascade, or delayed list, is perhaps the simplest possible form of iterator.
t y p e ’ a c a s c a d e = u n i t - > ’ a h e a d a n d ’ a h e a d =
| Nil
| C o n s of ’ a * ’ a c a s c a d e
Computation occurs on demand...
This definition offers an abstract, consumer-oriented view. It does not reveal :
I
whether a cascade has mutable internal state, or is pure ;
I
whether elements are stored in memory, or computed on demand ;
I
whether elements are re-computed when re-demanded, or memoized.
Cascades
A cascade, or delayed list, is perhaps the simplest possible form of iterator.
t y p e ’ a c a s c a d e = u n i t - > ’ a h e a d a n d ’ a h e a d =
| Nil
| C o n s of ’ a * ’ a c a s c a d e
...yielding either end-of-sequence...
This definition offers an abstract, consumer-oriented view. It does not reveal :
I
whether a cascade has mutable internal state, or is pure ;
I
whether elements are stored in memory, or computed on demand ;
I
whether elements are re-computed when re-demanded, or memoized.
Cascades
A cascade, or delayed list, is perhaps the simplest possible form of iterator.
t y p e ’ a c a s c a d e = u n i t - > ’ a h e a d a n d ’ a h e a d =
| Nil
| C o n s of ’ a * ’ a c a s c a d e
...or an element and a tail.
This definition offers an abstract, consumer-oriented view. It does not reveal :
I
whether a cascade has mutable internal state, or is pure ;
I
whether elements are stored in memory, or computed on demand ;
I
whether elements are re-computed when re-demanded, or memoized.
Cascades
A cascade, or delayed list, is perhaps the simplest possible form of iterator.
t y p e ’ a c a s c a d e = u n i t - > ’ a h e a d a n d ’ a h e a d =
| Nil
| C o n s of ’ a * ’ a c a s c a d e
This definition offers an abstract, consumer-oriented view. It does not reveal :
I
whether a cascade has mutable internal state, or is pure ;
I
whether elements are stored in memory, or computed on demand ;
I
whether elements are re-computed when re-demanded, or memoized.
Cascades
A cascade, or delayed list, is perhaps the simplest possible form of iterator.
t y p e ’ a c a s c a d e = u n i t - > ’ a h e a d a n d ’ a h e a d =
| Nil
| C o n s of ’ a * ’ a c a s c a d e
This definition offers an abstract, consumer-oriented view. It does not reveal :
I
whether a cascade has mutable internal state, or is pure ;
I
whether elements are stored in memory, or computed on demand ;
I
whether elements are re-computed when re-demanded, or memoized.
Cascades are easy to build and use because they are
“just like lists”.
A cascade – for hash tables
Constructing a cascade is like constructing a list of all key-value pairs...
l e t r e c c a s c a d e _ a u x d a t a i b = m a t c h b w i t h
| M o r e ( k , x , b ) - >
C o n s ( ( k , x ) ,
f u n () - > c a s c a d e _ a u x d a t a i b )
| V o i d - >
l e t i = i + 1 in
if i < A r r a y . l e n g t h d a t a t h e n c a s c a d e _ a u x d a t a i d a t a .( i ) e l s e
Nil l e t c a s c a d e h =
l e t d a t a = h . d a t a in l e t b = d a t a . ( 0 ) in f u n () - >
c a s c a d e _ a u x d a t a 0 b
A cascade – for hash tables
Constructing a cascade is like constructing a list of all key-value pairs...
l e t r e c c a s c a d e _ a u x d a t a i b = m a t c h b w i t h
| M o r e ( k , x , b ) - >
C o n s ( ( k , x ) ,
f u n () - > c a s c a d e _ a u x d a t a i b )
| V o i d - >
l e t i = i + 1 in
if i < A r r a y . l e n g t h d a t a t h e n c a s c a d e _ a u x d a t a i d a t a .( i ) e l s e
Nil l e t c a s c a d e h =
l e t d a t a = h . d a t a in l e t b = d a t a . ( 0 ) in f u n () - >
c a s c a d e _ a u x d a t a 0 b
...with a delay.
A cascade – for hash tables
Constructing a cascade is like constructing a list of all key-value pairs...
l e t r e c c a s c a d e _ a u x d a t a i b = m a t c h b w i t h
| M o r e ( k , x , b ) - >
C o n s ( ( k , x ) ,
f u n () - > c a s c a d e _ a u x d a t a i b )
| V o i d - >
l e t i = i + 1 in
if i < A r r a y . l e n g t h d a t a t h e n c a s c a d e _ a u x d a t a i d a t a .( i ) e l s e
Nil l e t c a s c a d e h =
l e t d a t a = h . d a t a in l e t b = d a t a . ( 0 ) in f u n () - >
c a s c a d e _ a u x d a t a 0 b
The cascade must not be
used after the table is
modified!
Specifying a cascade – in general
A cascade is a function that returns an element and a cascade.
We use an impredicative encoding of this co-inductive specification.
V a r i a b l e I : h p r o p .
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . D e f i n i t i o n c ˜ > Cascade xs :=
H e x i s t s S : l i s t A - > f u n c - > hprop , S xs c \*
\[ f o r a l l xs c , d u p l i c a b l e ( S xs c ) ] \*
\[ f o r a l l xs c , S xs c == > S xs c \* \[ p e r m i t t e d xs ]] \*
\[ f o r a l l xs c , app c [ tt ]
INV ( S xs c \* I ) P O S T ( fun o = >
m a t c h o w i t h
| Nil = > \[ c o m p l e t e xs ]
| C o n s x c = > S ( xs & x ) c end ) ].
Specifying a cascade – in general
A cascade is a function that returns an element and a cascade.
We use an impredicative encoding of this co-inductive specification.
V a r i a b l e I : h p r o p .
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . D e f i n i t i o n c ˜ > Cascade xs :=
H e x i s t s S : l i s t A - > f u n c - > hprop , S xs c \*
\[ f o r a l l xs c , d u p l i c a b l e ( S xs c ) ] \*
\[ f o r a l l xs c , S xs c == > S xs c \* \[ p e r m i t t e d xs ]] \*
\[ f o r a l l xs c , app c [ tt ]
INV ( S xs c \* I ) P O S T ( fun o = >
m a t c h o w i t h
| Nil = > \[ c o m p l e t e xs ]
| C o n s x c = > S ( xs & x ) c end ) ].
The cascade has internal
invariant S...
Specifying a cascade – in general
A cascade is a function that returns an element and a cascade.
We use an impredicative encoding of this co-inductive specification.
V a r i a b l e I : h p r o p .
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . D e f i n i t i o n c ˜ > Cascade xs :=
H e x i s t s S : l i s t A - > f u n c - > hprop , S xs c \*
\[ f o r a l l xs c , d u p l i c a b l e ( S xs c ) ] \*
\[ f o r a l l xs c , S xs c == > S xs c \* \[ p e r m i t t e d xs ]] \*
\[ f o r a l l xs c , app c [ tt ]
INV ( S xs c \* I ) P O S T ( fun o = >
m a t c h o w i t h
| Nil = > \[ c o m p l e t e xs ]
| C o n s x c = > S ( xs & x ) c end ) ].
...which must be duplicable.
A cascade is persistent.
Specifying a cascade – in general
A cascade is a function that returns an element and a cascade.
We use an impredicative encoding of this co-inductive specification.
V a r i a b l e I : h p r o p .
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . D e f i n i t i o n c ˜ > Cascade xs :=
H e x i s t s S : l i s t A - > f u n c - > hprop , S xs c \*
\[ f o r a l l xs c , d u p l i c a b l e ( S xs c ) ] \*
\[ f o r a l l xs c , S xs c == > S xs c \* \[ p e r m i t t e d xs ]] \*
\[ f o r a l l xs c , app c [ tt ]
INV ( S xs c \* I ) P O S T ( fun o = >
m a t c h o w i t h
| Nil = > \[ c o m p l e t e xs ]
| C o n s x c = > S ( xs & x ) c end ) ].
Calling c requires validity
and produces
another valid cascade.
Specifying a cascade – in general
A cascade is a function that returns an element and a cascade.
We use an impredicative encoding of this co-inductive specification.
V a r i a b l e I : h p r o p .
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . D e f i n i t i o n c ˜ > Cascade xs :=
H e x i s t s S : l i s t A - > f u n c - > hprop , S xs c \*
\[ f o r a l l xs c , d u p l i c a b l e ( S xs c ) ] \*
\[ f o r a l l xs c , S xs c == > S xs c \* \[ p e r m i t t e d xs ]] \*
\[ f o r a l l xs c , app c [ tt ]
INV ( S xs c \* I ) P O S T ( fun o = >
m a t c h o w i t h
| Nil = > \[ c o m p l e t e xs ]
| C o n s x c = > S ( xs & x ) c end ) ].
The spec is parameterized
over permitted and complete.
Specifying a cascade – in general
A cascade is a function that returns an element and a cascade.
We use an impredicative encoding of this co-inductive specification.
V a r i a b l e I : h p r o p .
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . D e f i n i t i o n c ˜ > Cascade xs :=
H e x i s t s S : l i s t A - > f u n c - > hprop , S xs c \*
\[ f o r a l l xs c , d u p l i c a b l e ( S xs c ) ] \*
\[ f o r a l l xs c , S xs c == > S xs c \* \[ p e r m i t t e d xs ]] \*
\[ f o r a l l xs c , app c [ tt ]
INV ( S xs c \* I ) P O S T ( fun o = >
m a t c h o w i t h
| Nil = > \[ c o m p l e t e xs ]
| C o n s x c = > S ( xs & x ) c end ) ].
The consumer may assume
that the partial sequence
produced so far is permitted.
Specifying a cascade – in general
A cascade is a function that returns an element and a cascade.
We use an impredicative encoding of this co-inductive specification.
V a r i a b l e I : h p r o p .
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . D e f i n i t i o n c ˜ > Cascade xs :=
H e x i s t s S : l i s t A - > f u n c - > hprop , S xs c \*
\[ f o r a l l xs c , d u p l i c a b l e ( S xs c ) ] \*
\[ f o r a l l xs c , S xs c == > S xs c \* \[ p e r m i t t e d xs ]] \*
\[ f o r a l l xs c , app c [ tt ]
INV ( S xs c \* I ) P O S T ( fun o = >
m a t c h o w i t h
| Nil = > \[ c o m p l e t e xs ]
| C o n s x c = > S ( xs & x ) c end ) ].
Upon termination, the consumer may deduce that
the sequence is complete.
Specifying a cascade – in general
A cascade is a function that returns an element and a cascade.
We use an impredicative encoding of this co-inductive specification.
V a r i a b l e I : h p r o p .
V a r i a b l e s p e r m i t t e d c o m p l e t e : l i s t A - > P r o p . D e f i n i t i o n c ˜ > Cascade xs :=
H e x i s t s S : l i s t A - > f u n c - > hprop , S xs c \*
\[ f o r a l l xs c , d u p l i c a b l e ( S xs c ) ] \*
\[ f o r a l l xs c , S xs c == > S xs c \* \[ p e r m i t t e d xs ]] \*
\[ f o r a l l xs c , app c [ tt ]
INV ( S xs c \* I ) P O S T ( fun o = >
m a t c h o w i t h
| Nil = > \[ c o m p l e t e xs ]
| C o n s x c = > S ( xs & x ) c end ) ].
The cascade has access to
an underlying data structure.
Specifying a cascade – for hash tables
T h e o r e m c a s c a d e _ s p e c : f o r a l l h M s , app MK . c a s c a d e [ h ]
INV ( h ˜ > TableInState M s) P O S T ( fun c = >
c ˜ > Cascade
( h ˜ > TableInState M s) ( p e r m i t t e d M ) ( c o m p l e t e M ) nil
).
“Concurrent modifications” are disallowed.
Specifying a cascade – for hash tables
T h e o r e m c a s c a d e _ s p e c : f o r a l l h M s , app MK . c a s c a d e [ h ]
INV ( h ˜ > TableInState M s) P O S T ( fun c = >
c ˜ > Cascade
( h ˜ > TableInState M s) ( p e r m i t t e d M ) ( c o m p l e t e M ) nil
).
Same predicates permitted and complete as in fold.
“Concurrent modifications” are disallowed.
Specifying a cascade – for hash tables
T h e o r e m c a s c a d e _ s p e c : f o r a l l h M s , app MK . c a s c a d e [ h ]
INV ( h ˜ > TableInState M s) P O S T ( fun c = >
c ˜ > Cascade
( h ˜ > TableInState M s) ( p e r m i t t e d M ) ( c o m p l e t e M ) nil
).
The cascade can be used only as long as the table
remains in state s.
“Concurrent modifications” are disallowed.
The data structure
First-order operations
Iteration via fold
Iteration via cascades
Conclusion
Conclusion
I have shown arguably nice specifications expressed in vanilla Separation Logic.
I
No magic wands, fractional permissions, or other black wizardry.
A few statistics :
I
Under 150loc of OCaml code.
I
Dictionaries about 600loc of Coq specs and proofs.
I
Hash tables about 1500loc of Coq specs and proofs.
Total effort about 15 man.days, but a lot of expertise still required.
Future work :
I
verifying more data structures ;
I