Object Invariants in Dynamic Contexts
180 likes | 335 Views
Object Invariants in Dynamic Contexts. K.R.M. Leino and P. Muller 15-819: Objects and Aspects Presented by Jonathan Aldrich. Outline. Problem Modular enforcement of invariants Separate reasoning with callbacks and inheritance Solution Class invariants Partial packing and unpacking
Object Invariants in Dynamic Contexts
E N D
Presentation Transcript
Object Invariantsin Dynamic Contexts K.R.M. Leino and P. Muller 15-819: Objects and Aspects Presented by Jonathan Aldrich
Outline • Problem • Modular enforcement of invariants • Separate reasoning with callbacks and inheritance • Solution • Class invariants • Partial packing and unpacking • “Ownership” relation • Discussion
Callbacks and Invariants class T { int a, b ; invariant 0 <= a < b public T( ) { a := 0 ; b := 3 ; } public void m(. . .) { int k := 100/(b - a) ; a := a +3 ; P(. . .) ; b := (k + 4) . b ; } } • What if P calls m? • Soundness: Must ensure it doesn’t, or that the invariant is not assumed by m
Inheritance and Invariants class Derived extends Base { int a, b ; invariant 0 <= a < b public void m(. . .) { int k := 100/(b - a) ; super.m(. . .) ; a := a +3 ; P(. . .) ; b := (k + 4) . b ; } } • What about the invariants of Base? • Modularity: would like to assume that super call ensures them • Need notion entering and leaving a class scope
Class Invariants class C extends B { int w ; invariant w < 100 ; . . . } class B extends A { int z ; invariant y < z ; . . . } class A extends object { int x, y ; invariant x < y ; . . . } • inv = A • Invariant A must hold • B and C may or may not hold
Class Invariants class C extends B { int w ; invariant w < 100 ; . . . } class B extends A { int z ; invariant y < z ; . . . } class A extends object { int x, y ; invariant x < y ; . . . } o.z = y+1; pack o as B; pack o as C; continue…
Class Invariants class C extends B { int w ; invariant w < 100 ; . . . } class B extends A { int z ; invariant y < z ; . . . } class A extends object { int x, y ; invariant x < y ; . . . } o.z = y+1; pack o as B; pack o as C; continue…
Class Invariants class C extends B { int w ; invariant w < 100 ; . . . } class B extends A { int z ; invariant y < z ; . . . } class A extends object { int x, y ; invariant x < y ; . . . } o.z = y+1; pack o as B; pack o as C; continue…
Class Invariants class C extends B { int w ; invariant w < 100 ; . . . } class B extends A { int z ; invariant y < z ; . . . } class A extends object { int x, y ; invariant x < y ; . . . } o.z = y+1; pack o as B; pack o as C; continue…
Inheritance and Invariants class Derived extends Base { int a, b ; invariant 0 <= a < b public void m(. . .) { unpackthis from Derived int k := 100/(b - a) ; super.m(. . .) ; // unpacks and re-packs Base a := a +3 ; P(. . .) ; b := (k + 4) . b ; packthis as Derived } } • Incremental unpacking and re-packing supports modular verification
Callbacks and Invariants class T { int a, b ; invariant 0 <= a < b public T( ) { a := 0 ; b := 3 ; } public void m(. . .) requiresthis . inv = T { unpackthis from T ; int k := 100/(b - a) ; a := a +3 ; P(. . .) ; b := (k + 4) . b ; packthis as T ; } } • What if P calls m? • It must first restore the invariant and pack this as T, because m’s precondition assumes that T is packed
Invariants and Sub-objects class BTree { int i ; BTree left, right ; invariant (left != null) left.i < i (right != null) right.i ≥ i ; } • How to ensure invariant modularly? • What if someone modifies left.i without going through the current object?
Ownership, Boogie Style • p is owned by o at T • p.owner = [o,T] • p is committed • p.committed • All invariants hold for committed objects • p.committed p.inv = type(p) • Object is committed when owner is packed • p.owner = [o,T] (p.committed o.inv ≤ T)
Invariants and Sub-objects class BTree { inti ; rep BTree left, right ; invariant left.owner = [this, BTree] ; invariant right.owner = [this, BTree] ; invariant(left != null) left.i < i (right != null) right.i ≥ i ; } • Invariant can rely on owned objects • unpack this, invariants hold for children • children can’t be unpacked (and thus can’t have broken invariants) unless owner is first unpacked
Ownership Transfer transferable class Possession {. . .} class Person { rep Possession possn ; void donateTo(Person p) requires ¬committed È inv = Person ; requires possn = nullÈ Ètype(possn) = Possession ; requires p = null È p = this È ¬p.committed È p.inv = Person ; modifies possn, p.possn ; { unpack this from Person ; unpack p from Person ; unpack possn from Possession ; transfer possn to [p, Person] ; pack possn as Possession ; p.possn := possn ; pack p as Person ; possn := null ; pack this as Person ; } . . . }
Ownership in Boogie Allows external aliases (but can’t mutate through them) Supports ownership transfer Heavyweight: must track precisely Classical Ownership External aliases No ownership transfer Lightweight: can track with types Is “ownership” really Ownership? I find this all a bit misleading… probably better to use a different term
explain visibility rules • field update rules
Discussion • Practicality • Requires very careful tracking of containing object state • Forbids iterators, etc. • Strong conditions for transfer • Lessons for informal reasoning? • Applicability to aspects?