A Considerate Specification of the Composite Pattern

Slides:



Advertisements
Similar presentations
Chapter 13. Red-Black Trees
Advertisements

Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 18 Program Correctness To treat programming.
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
In this episode of The Verification Corner, Rustan Leino talks about Loop Invariants. He gives a brief summary of the theoretical foundations and shows.
Semantics Static semantics Dynamic semantics attribute grammars
PZ03D Programming Language design and Implementation -4th Edition Copyright©Prentice Hall, PZ03D - Program verification Programming Language Design.
Non-monotonic Properties for Proving Correctness in a Framework of Compositional Logic Koji Hasebe Mitsuhiro Okada (Dept. of Philosophy, Keio University)
A survey of techniques for precise program slicing Komondoor V. Raghavan Indian Institute of Science, Bangalore.
1 Semantic Description of Programming languages. 2 Static versus Dynamic Semantics n Static Semantics represents legal forms of programs that cannot be.
Changing perspective can be useful Relating alternative logics for automatic software verification Alex Summers (ETH Zurich) partly based on joint work.
CS 206 Introduction to Computer Science II 02 / 20 / 2009 Instructor: Michael Eckmann.
CS 206 Introduction to Computer Science II 10 / 01 / 2008 Instructor: Michael Eckmann.
Validating Streaming XML Documents Luc Segoufin & Victor Vianu Presented by Harel Paz.
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 18 Program Correctness To treat programming.
Well-cooked Spaghetti: Weakest-Precondition of Unstructured Programs Mike Barnett and Rustan Leino Microsoft Research Redmond, WA, USA.
Chapter 12 Trees. Copyright © 2005 Pearson Addison-Wesley. All rights reserved Chapter Objectives Define trees as data structures Define the terms.
Reasoning about Multiple Related Abstractions with MultiStar Stephan van Staden, Cristiano Calcagno Chair of Software Engineering.
1/25 Pointer Logic Changki PSWLAB Pointer Logic Daniel Kroening and Ofer Strichman Decision Procedure.
Week 7 - Wednesday.  What did we talk about last time?  Recursive running time  Master Theorem  Introduction to trees.
50.003: Elements of Software Construction Week 8 Composing Thread-safe Objects.
Model Programs for Preserving Composite Invariants SAVCBS 2008 Challenge Problem Solution by Steve Shaner, Hridesh Rajan, Gary T. Leavens Iowa State and.
Refinements to techniques for verifying shape analysis invariants in Coq Kenneth Roe GBO Presentation 9/30/2013 The Johns Hopkins University.
CMSC 341 B- Trees D. Frey with apologies to Tom Anastasio.
Red–black trees.  Define the red-black tree properties  Describe and implement rotations  Implement red-black tree insertion  We will skip red-black.
Secure Component Composition for Personal Ubiquitous Computing Project Overview and Potential Techniques —————— 16 th May 2003 —————— David Llewellyn-Jones.
Verification of Programs with Inspector Methods Bart Jacobs and Frank Piessens Dept. CS, K.U.Leuven, Belgium.
Formal Specification of Intrusion Signatures and Detection Rules By Jean-Philippe Pouzol and Mireille Ducassé 15 th IEEE Computer Security Foundations.
A Universe-Type-Based Verification Technique for Mutable Static Fields and Methods Alexander J Summers Sophia Drossopoulou Imperial College London Peter.
Chapter 6 Introduction to Defining Classes. Objectives: Design and implement a simple class from user requirements. Organize a program in terms of a view.
COP4020 Programming Languages Introduction to Axiomatic Semantics Prof. Robert van Engelen.
Programming by Contract 2 Object-oriented languages Class Invariants.
Spec# Andreas Vida. Motivation Correct and maintainable software Correct and maintainable software Cost effective software production Cost effective software.
Lecture 5 1 CSP tools for verification of Sec Prot Overview of the lecture The Casper interface Refinement checking and FDR Model checking Theorem proving.
Review of Parnas’ Criteria for Decomposing Systems into Modules Zheng Wang, Yuan Zhang Michigan State University 04/19/2002.
SAFE KERNEL EXTENSIONS WITHOUT RUN-TIME CHECKING George C. Necula Peter Lee Carnegie Mellon U.
CSSE501 Object-Oriented Development. Chapter 10: Subclasses and Subtypes  In this chapter we will explore the relationships between the two concepts.
Week 7 - Wednesday.  What did we talk about last time?  Recursive running time  Master Theorem  Symbol tables.
DBC NOTES. Design By Contract l A contract carries mutual obligations and benefits. l The client should only call a routine when the routine’s pre-condition.
Design of Tree Algorithm Objectives –Learning about satisfying safety and liveness of a distributed program –Apply the method of utilizing invariants and.
Object Design More Design Patterns Object Constraint Language Object Design Specifying Interfaces Review Exam 2 CEN 4010 Class 18 – 11/03.
COMPOSITE PATTERN NOTES. The Composite pattern l Intent Compose objects into tree structures to represent whole-part hierarchies. Composite lets clients.
8/3/2007CMSC 341 BTrees1 CMSC 341 B- Trees D. Frey with apologies to Tom Anastasio.
Towards a Semantic Model for Java Wildcards Sophia Drossopoulou Mariangiola Dezani-Ciancaglini Imperial College London Università di Torino Italy Nicholas.
Chapter 3 of Programming Languages by Ravi Sethi
Opeoluwa Matthews, Jesse Bingham, Daniel Sorin
Further with Hoare Logic Sections 6.12, 6.10, 6.13
The Relationship Between Separation Logic and Implicit Dynamic Frames
Action Editor Storyboard
Hans Bodlaender, Marek Cygan and Stefan Kratsch
Spring 2016 Program Analysis and Verification
Week 6 - Wednesday CS221.
Modular Verification of Message Passing Programs
Discrete Structures for Computer Science
Red-Black Trees Motivations
CMSC 341 Lecture 10 B-Trees Based on slides from Dr. Katherine Gibson.
Lecture 9 Algorithm Analysis
Programming Languages 2nd edition Tucker and Noonan
B- Trees D. Frey with apologies to Tom Anastasio
Lecture 9 Algorithm Analysis
B- Trees D. Frey with apologies to Tom Anastasio
Lecture 9 Algorithm Analysis
CSCI1600: Embedded and Real Time Software
B- Trees D. Frey with apologies to Tom Anastasio
This Lecture Substitution model
Software Design Lecture : 35.
Chapter 20: Binary Trees.
Assertions References: internet notes; Bertrand Meyer, Object-Oriented Software Construction; 4/25/2019.
Programming Languages 2nd edition Tucker and Noonan
Lattice Motivation: Maintaining relationships between elements of two
Software Design Lecture : 36.
Presentation transcript:

A Considerate Specification of the Composite Pattern Alexander J. Summers Sophia Drossopoulou Imperial College London Imperial College London

Overview Specification of the Composite pattern SAVCBS challenge problem last year Invariant protocol based on Middelkoop et. al. 2006 Idea: “Considerate Reasoning” (IWACO 2009) objects are concerned with each others’ invariants Implementation and verification in Boogie2 Encoding the invariant protocol Simplifying the resulting proof obligations Practical handling of quantified formulas

The Composite pattern A tree whose nodes preserve properties related to all their descendant leaves. Subtrees may be added directly without first visiting their parents. We ignore subclassing issues for this talk, and treat a single class Composite

The Composite pattern suggested as a specification/verification challenge by Mueller, Leavens and Poetzsch-Heffter Various solutions proposed at SACVBS’08 We describe its specification and verification using invariants, adapting approach suggested by Middelkoop et. al. What we’re going to talk about the effect of different connectives on term calculi Write this at the end, when all other slides are done.#

The Composite class class Composite int total; Composite parent; Composite[] components; int count; void addComponent(Composite c); … }

The Composite class 7 class Composite int total; Composite parent; Composite[] components; int count; void addComponent(Composite c); … } 4 3 2 2 2 1

The Composite class 7 class Composite int total; Composite parent; Composite[] components; int count; void addComponent(Composite c); … } 4 3 2 2 2 1 The field parent points to the parent node. The fields components and count maintain pointers to all children – i.e., the inverse of parent.

The Composite - invariant 2 2 2 1

The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. 2 2 2 1

The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. 7 2 2 2 1

The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. 7 4 2 2 2 1

The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. 7 4 3 2 2 2 1

The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. P(n) <=> n.total =  (lf.total), where lf a leaf under n 7 4 3 2 2 2 1

The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. P(n) <=> n.total =  (lf.total), where lf a leaf under n 7 4 3 2 2 2 1

The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. P(n) <=> n.total =  (lf.total), where lf a leaf under n 7 4 3 2 2 2 1 P(n) is a non-local predicate

The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. 2 2 2 1

The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. Q(n) <=> n.total =  (n’.total), where n’.parent=this 2 2 2 1

The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. Q(n) <=> n.total =  (n’.total), where n’.parent=this 4 2 2 2 1

The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. Q(n) <=> n.total =  (n’.total), where n’.parent=this 4 3 2 2 2 1

The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. Q(n) <=> n.total =  (n’.total), where n’.parent=this 7 4 3 2 2 2 1

Local invariants achieve as much P(n)  n.total =  (lf.total), where lf a leaf under n P(n) is non-local Q(n)  n.total =  (n’.total), where n’.parent=this Q(n) is local P(n) is stronger than Q(n) n. P(n)  n. Q(n) We will be using Q(n) as the invariant for n InvTwo: total == 1 + Sum(i=0..count)::components[i].total

The Composite - code void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total ); }

The Composite - code void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total ); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t);

The Composite - code this c void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total ); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this c

The Composite - code this c void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total ); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this c

The Composite - code this c void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this c

The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this

The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this

The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this

The Composite - add a subtree The Composite - code The Composite - add a subtree void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this

The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this

The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this

The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this

The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this

The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this

The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1

The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvOne: total > 0 && count ≥ 0

The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total

The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvThree: i::components[i].parent == this

The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvThree: i::components[i].parent == this InvFour: this.parent != null  i::this.parent.components[i] == this

The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvThree: i::components[i].parent == this InvFour: this.parent != null  i::this.parent.components[i] == this Essentially, parent and components are inverses

Visible States Semantics One basic philosophy for multi-object invariants Idea: invariants can be temporarily broken Must be fixed by the end of each method body Must also be fixed before making further calls In simplest form, all invariants hold at these points Many invariant protocols are based on this idea We use a variant based on Middelkoop et. al. First, basic visible states implemented in Boogie2

Visible State Semantics in Boogie2 public void addComponent(Composite c) { components[count] = c; count++; c.parent = this; this.addToTotal(c.total); }

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); }

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); }

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); } assume o :: InvOne(o)

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); } assume o :: InvOne(o) assume o :: InvTwo(o) assume o :: InvThree(o) assume o :: InvFour(o)

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); }

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); assert all invariants.. }

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); assert all invariants.. } assert o :: InvOne(o) assert o :: InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); assert all invariants.. }

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }

Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } But, addToTotal is meant to fix an invariant which is currently broken!

Handling “broken” invariants We need to allow exceptions to visible states rules Want to allow an invariant to be broken for a call Idea: add a specification construct broken Method signatures can declare “broken” invariants: InvTwo(this) need not hold before calling However, must be established by the method end Related to the INC construct of Middelkoop et. al. // broken: InvTwo(this) private void addToTotal() { ...

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } private void addToTotal() { ...

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ...

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ...

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ... assert o :: InvOne(o) assert o :: InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ... assert o :: InvOne(o) assert o :: InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ... assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); assert all invariants.. } assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)

Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); assert all invariants.. }

Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover

Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. }

Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o)

Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)

Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)

Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)

Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)

Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover Which assertions trivial, and which require work? void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)

Coop-sets to track invariants Idea: track which invariants depend on which fields Middelkoop et. al. – each field gets a “coop set” Declares which invariants may be broken by modifying this field Coop sets consist of pairs (I, P), where... I names an invariant which depends on the field P is a predicate describing when this invariant might be broken by modifying the field, in which: this denotes the object whose field is modified o denotes the object whose invariant may be broken

Coop-sets to track invariants

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ...

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop:

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop:

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this)

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this)

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this)

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this)

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this)

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this)

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this) // (InvTwo, i :: o.components[i] == this)

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this) // (InvTwo, i :: o.components[i] == this)

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this) // (InvTwo, i :: o.components[i] == this) Use the coop-sets to calculate the vulnerable invariants

Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this) // (InvTwo, i :: o.components[i] == this) Use the coop-sets to calculate the vulnerable invariants Note: the objects o are not obviously reachable from this

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); assert all invariants.. }

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); assert all invariants.. }

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total);

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total);

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; Vulnerable Invariants

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; // coop: (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; // coop: (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; // coop: (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; // coop: (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o) Note: coop wrong

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvThree(this)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvThree(this), o :: o.parent==this  InvFour(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvThree(this), o :: o.parent==this  InvFour(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvThree(this), o :: o.parent==this  InvFour(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvThree(this)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvThree(this)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite parent; // coop: (InvFour,o==this) // (InvThree,(i :: this==o.components[i])) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite parent; // coop: (InvFour,o==this) // (InvThree,(i :: this==o.components[i])) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvFour(c)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite parent; // coop: (InvFour,o==this) // (InvThree,(i :: this==o.components[i])) Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvFour(c), o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvFour(c), o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvFour(c), o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvTwo(this), InvFour(c), o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this  InvFour(o), InvOne(this), InvFour(c), o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants aInvThree(this), ao :: o.parent==this  InvFour(o), aInvOne(this), aInvFour(c), ao :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants asInvThree(this), aso :: o.parent==this  InvFour(o), asInvOne(this), asInvFour(c), aso :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assInvThree(this), asso :: o.parent==this  InvFour(o), assInvOne(this), assInvFour(c), asso :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants asseInvThree(this), asseo :: o.parent==this  InvFour(o), asseInvOne(this), asseInvFour(c), asseo :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants asserInvThree(this), assero :: o.parent==this  InvFour(o), asserInvOne(this), asserInvFour(c), assero :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assertInvThree(this), asserto :: o.parent==this  InvFour(o), assertInvOne(this), assertInvFour(c), asserto :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) FEWER INVARIANTS ASSERTED Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) FEWER INVARIANTS ASSERTED Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this  InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Refining vulnerable invariants InvThree and InvFour express that components and parent are “inverses” If we use this information, we can refine assertions For example: assert o :: (i :: c==o.components[i])  InvThree(o) “those objects which have c in their components” The only possible such object is c.parent : assert (c.parent != null)  InvThree(c.parent) This assertion concerns a (single) object to which we have direct field access This reduces the burden of work on the prover

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); o.parent==this  othis.components Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); o.parent==this  othis.components Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i])  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i])  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i])  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); co.components  c.parent == o Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i])  InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i])  InvThree(o)

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); co.components  c.parent == o Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i])  InvFour(o), assert InvOne(this), assert InvFour(c), assert (c.parent != null)  InvThree(c.parent)

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i])  InvFour(o), assert InvOne(this), assert InvFour(c), assert (c.parent != null)  InvThree(c.parent)

Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i])  InvFour(o), assert InvOne(this), assert InvFour(c), assert (c.parent != null)  InvThree(c.parent)

Quantifiers in assumptions Assuming all invariants is logically very powerful However, in practice this can give too much information to the theorem prover assume o :: InvOne(o) .... InvOne(this)

Quantifiers in assumptions Assuming all invariants is logically very powerful However, in practice this can give too much information to the theorem prover assume o :: InvOne(o) .... InvOne(this), InvOne(this.parent)

Quantifiers in assumptions Assuming all invariants is logically very powerful However, in practice this can give too much information to the theorem prover assume o :: InvOne(o) .... InvOne(this), InvOne(this.parent), InvOne(this.parent.parent)... We can use “triggers” on quantified formulas to control when the prover instantiates them Rule: the prover has to “know about” a term which matches the trigger, to be allowed to instantiate

Quantifiers in assumptions Without choosing appropriate triggers, we get looping and unpredictable results Invariant definitions are guarded by triggers: The invariant name, e.g. InvOne(o) Some additional triggers: hint when it might be useful Invariants assumed/asserted in code are also guarded: Only instantiate if the invariant is determined to be relevant at some point in the method body. This can be by explicitly mentioning it, or because its definition is triggered as above. Resulting specification is well-behaved!

Results Our specification in Boogie encodes our intended invariant-based argument naturally and precisely The specification verifies (in about 5 seconds) No additional assertions are needed in the code: only those specified by the invariant protocol The calculation of vulnerable invariants from coop-sets could be easily automated The calculation of coop-sets themselves is by hand, but we believe could be partially automated The essential simplification is gained by knowing “inverse” relationships between fields

Conclusions and Future Work Invariant-based approach handles this example Resulting specification is simple, compared with “direct” approaches, and could be automated Simplifications of vulnerable invariants require some extra work The approach extends to other more-complex examples (with cycles etc.). The treatment of invariants we have used does not extend easily to client-provider relationships A combination with other approaches (e.g., ownership) would be more flexible

Finally…

Any questions? Thank you for listening! What we’re going to talk about the effect of different connectives on term calculi Write this at the end, when all other slides are done.#