Ownership Types for Object Encapsulation Barbara Liskov Chandrasekhar Boyapati Liuba Shrira Laboratory for Computer Science Massachusetts Institute of.

Slides:



Advertisements
Similar presentations
Writing specifications for object-oriented programs K. Rustan M. Leino Microsoft Research, Redmond, WA, USA 21 Jan 2005 Invited talk, AIOOL 2005 Paris,
Advertisements

Containers CMPS Reusable containers Simple data structures in almost all nontrivial programs Examples: vectors, linked lists, stacks, queues, binary.
The Line Class Suppose you are involved in the development of a large mathematical application, and this application needs an object to represent a Line.
CSE 331 SOFTWARE DESIGN & IMPLEMENTATION DEBUGGING Autumn 2011 Bug-Date: Sept 9, 1947.
Verification of Multithreaded Object- Oriented Programs with Invariants Bart Jacobs, K. Rustan M. Leino, Wolfram Schulte.
Mutability SWE 332 Fall 2011 Paul Ammann. SWE 3322 Data Abstraction Operation Categories Creators Create objects of a data abstraction Producers Create.
Data Abstraction II SWE 619 Software Construction Last Modified, Spring 2009 Paul Ammann.
Replication and Consistency (2). Reference r Replication in the Harp File System, Barbara Liskov, Sanjay Ghemawat, Robert Gruber, Paul Johnson, Liuba.
The Java Assert Statement. 2 Assert A Java statement in JDK 1.4 & newer Intent: enables code to test assumptions. E.g., a method that calculates a particle’s.
C. FlanaganSAS’04: Type Inference Against Races1 Type Inference Against Races Cormac Flanagan UC Santa Cruz Stephen N. Freund Williams College.
Ownership Types for Safe Programming: Preventing Data Races and Deadlocks Chandrasekhar Boyapati Robert Lee Martin Rinard Laboratory for Computer Science.
Alias Annotations for Program Understanding Jonathan Aldrich Valentin Kostadinov Craig Chambers University of Washington.
Software Testing and Quality Assurance
Chandrasekhar Boyapati Laboratory for Computer Science Massachusetts Institute of Technology Ownership Types for Safe Programming.
Principles of Object-Oriented Software Development Behavioral refinement.
A Type System for Preventing Data Races and Deadlocks in the Java Virtual Machine Language Pratibha Permandla Michael Roberson Chandrasekhar Boyapati University.
Laboratory for Computer Science Massachusetts Institute of Technology Ownership Types for Safe Region-Based Memory Management in Real-Time Java Chandrasekhar.
A Parameterized Type System for Race-Free Java Programs Chandrasekhar Boyapati Martin Rinard Laboratory for Computer Science Massachusetts Institute of.
29-Jun-15 Java Concurrency. Definitions Parallel processes—two or more Threads are running simultaneously, on different cores (processors), in the same.
Ownership Types for Object Encapsulation Authors:Chandrasekhar Boyapati Barbara Liskov Liuba Shrira Presented by: Charles Lin Course: CMSC 631.
Software Upgrades in Distributed Systems Barbara Liskov MIT Laboratory for Computer Science October 23, 2001.
16-Aug-15 Air Force Institute of Technology Electrical and Computer Engineering Object-Oriented Programming in Java Topic : Interfaces, Copying/Cloning,
CS 1031 C++: Object-Oriented Programming Classes and Objects Template classes Operator Overloading Inheritance Polymorphism.
REFACTORING Lecture 4. Definition Refactoring is a process of changing the internal structure of the program, not affecting its external behavior and.
1 Abstraction  Identify important aspects and ignore the details  Permeates software development programming languages are abstractions built on hardware.
1 CSC 221: Computer Programming I Spring 2010 interaction & design  modular design: roulette game  constants, static fields  % operator, string equals.
ROBERT BOCCHINO, ET AL. UNIVERSAL PARALLEL COMPUTING RESEARCH CENTER UNIVERSITY OF ILLINOIS A Type and Effect System for Deterministic Parallel Java *Based.
Question of the Day  On a game show you’re given the choice of three doors: Behind one door is a car; behind the others, goats. After you pick a door,
Question of the Day  On a game show you’re given the choice of three doors: Behind one door is a car; behind the others, goats. After you pick a door,
Generic Ownership for Generic Java Alex Potanin, Dave Clarke (CWI) James Noble, Robert Biddle (Carleton)
Retro: Modular and efficient retrospection in a database Ross Shaull Liuba Shrira Brandeis University.
Introduction CS 3358 Data Structures. What is Computer Science? Computer Science is the study of algorithms, including their  Formal and mathematical.
Existential Quantification for Variant Ownership Nicholas Cameron Sophia Drossopoulou Imperial College London (Victoria University of Wellington)‏
Design Patterns Gang Qian Department of Computer Science University of Central Oklahoma.
8 1 Chapter 8 Advanced SQL Database Systems: Design, Implementation, and Management, Seventh Edition, Rob and Coronel.
A Universe-Type-Based Verification Technique for Mutable Static Fields and Methods Alexander J Summers Sophia Drossopoulou Imperial College London Peter.
Dynamic Data Structures and Generics Chapter 10. Outline Vectors Linked Data Structures Introduction to Generics.
Data Abstraction SWE 619 Software Construction Last Modified, Spring 2009 Paul Ammann.
Understanding ADTs CSE 331 University of Washington.
ISBN Chapter 11 Abstract Data Types and Encapsulation Concepts.
The Java Assertion. 2 Assertion A Java statement in JDK 1.4 & newer Intent: enables code to test assumptions. E.g., a method that calculates the a particle’s.
CSSE501 Object-Oriented Development. Chapter 10: Subclasses and Subtypes  In this chapter we will explore the relationships between the two concepts.
Iteration Abstraction SWE Software Construction Fall 2009.
Object Oriented Programming. OOP  The fundamental idea behind object-oriented programming is:  The real world consists of objects. Computer programs.
/ PSWLAB Thread Modular Model Checking by Cormac Flanagan and Shaz Qadeer (published in Spin’03) Hong,Shin Thread Modular Model.
CHAPTER 07 Arrays and Vectors (part II). OBJECTIVES In this part you will learn:  To pass arrays to functions.  Basic searching techniques.
David Evans CS201j: Engineering Software University of Virginia Computer Science Lecture 10: Programming Exceptionally.
CSE 501N Fall ‘09 10: Introduction to Collections and Linked Lists 29 September 2009 Nick Leidenfrost.
Lazy Modular Upgrades in Persistent Object Stores Chandrasekhar Boyapati, Barbara Liskov, Liuba Shrira, Chuang-Hue Moh, Steven Richman MIT CSAIL October.
David Evans CS201J: Engineering Software University of Virginia Computer Science Lecture 7: A Tale of Two Graphs (and.
David Evans CS201J: Engineering Software University of Virginia Computer Science Lecture 5: Implementing Data Abstractions.
Reasoning and Design (and Assertions). How to Design Your Code The hard way: Just start coding. When something doesn’t work, code some more! The easier.
Jeremy Nimmer, page 1 Automatic Generation of Program Specifications Jeremy Nimmer MIT Lab for Computer Science Joint work with.
EECE 310: Software Engineering
EECE 310: Software Engineering
Abstract Data Types and Encapsulation Concepts
Systems Programming 3rd laboratory Test_driven Development
Abstract Data Types Iterators Vector ADT Sections 3.1, 3.2, 3.3, 3.4
Object initialization: constructors
Iteration Abstraction
SWE 619 Software Construction Last Modified, Fall 2015 Paul Ammann
Lecture 4: Data Abstraction CS201j: Engineering Software
COMPUTER 2430 Object Oriented Programming and Data Structures I
Java Concurrency 17-Jan-19.
Lazy Type Changes in Object-oriented Databases
Java Concurrency.
Java Concurrency.
Java Concurrency 29-May-19.
Object Encapsulation CSC 422 Dr. Spiegel.
Upgrading Distributed Systems is not rsync
Presentation transcript:

Ownership Types for Object Encapsulation Barbara Liskov Chandrasekhar Boyapati Liuba Shrira Laboratory for Computer Science Massachusetts Institute of Technology {liskov, chandra,

Outline Object Encapsulation Object Encapsulation Ownership Types Ownership Types Upgrades in Persistent Object Stores Upgrades in Persistent Object Stores

Modular Reasoning Goal is local reasoning about correctness Goal is local reasoning about correctness  Prove a class meets its specification, using only specifications but not code of other classes Crucial when dealing with large programs Crucial when dealing with large programs Requires no interference from code outside the class Requires no interference from code outside the class  Objects must be encapsulated

Consider a Set object s implemented using a Vector object v Consider a Set object s implemented using a Vector object v Object Encapsulation v ~ ~ so Local reasoning about s is possible Local reasoning about s is possible  If objects outside s do not access v  That is, if v is encapsulated within s

Encapsulation In general, all objects that s depends on must be encapsulated within s In general, all objects that s depends on must be encapsulated within s s depends on x if mutations of x affect behavior of s s depends on x if mutations of x affect behavior of s  Leino, Nelson ( SCR ’00 )  Detlefs, Leino, Nelson ( SRC ’98 )

Examples Rep invariant for Set: no-dups Rep invariant for Set: no-dups  Then, size of vector is size of set  Then, remove stops at match Clearly, v must be inside s Clearly, v must be inside s s v

Examples What does no-dups mean? What does no-dups mean?  ! e1.equals(e2), for any elements e1 & e2 So set does not depend on elements if elements are immutable So set does not depend on elements if elements are immutable s v

Iterators and Encapsulation Iterators require access to representation Iterators require access to representation Okay if violations of encapsulation limited to the same module Okay if violations of encapsulation limited to the same module s v i

Ownership Types Goal is to enforce encapsulation statically Goal is to enforce encapsulation statically s v Programmer can declare s owns v Programmer can declare s owns v System ensures v is encapsulated in s System ensures v is encapsulated in s

Ownership Types Every object has an owner Every object has an owner Owner can be another object or world Owner can be another object or world Ownership relation forms a tree Ownership relation forms a tree Owner of an object cannot change Owner of an object cannot change world

Ownership Types for Encapsulation If an object owns objects it depends on If an object owns objects it depends on Then type system enforces encapsulation Then type system enforces encapsulation  If v is inside s and o is outside  Then o cannot access v v ~ ~ so

Ownership Types world

class TStack { TNode head; TNode head; void push(T value) {…} void push(T value) {…} T pop() {…} T pop() {…}} class TNode { TNode next; TNode next; T value; T value; …} class T {…} TStack Example (No Owners) value next head value next value next … … … TStack TNode T

TStack Example (With Owners) class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head;} class TNode  nodeOwner, TOwner  { TNode  nodeOwner, TOwner  next; TNode  nodeOwner, TOwner  next; T  TOwner  value; T  TOwner  value;} class T  TOwner  {…} TStack TNode T Classes are parameterized with owners

TStack Example class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head;} class TNode  nodeOwner, TOwner  { TNode  nodeOwner, TOwner  next; TNode  nodeOwner, TOwner  next; T  TOwner  value; T  TOwner  value;} class T  TOwner  {…} TStack TNode T First owner owns the “this” object

TStack Example class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head;} class TNode  nodeOwner, TOwner  { TNode  nodeOwner, TOwner  next; TNode  nodeOwner, TOwner  next; T  TOwner  value; T  TOwner  value;} class T  TOwner  {…} TStack TNode T TStack owns the “head” TNode

TStack Example class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head;} class TNode  nodeOwner, TOwner  { TNode  nodeOwner, TOwner  next; TNode  nodeOwner, TOwner  next; T  TOwner  value; T  TOwner  value;} class T  TOwner  {…} TStack TNode T The “next” TNode has the same owner as the “this” TNode All TNodes have the same owner

TStack Example class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head;} class TNode  nodeOwner, TOwner  { TNode  nodeOwner, TOwner  next; TNode  nodeOwner, TOwner  next; T  TOwner  value; T  TOwner  value;} class Client  clientOwner  { TStack  this, this  s1; TStack  this, this  s1; TStack  this, world  s2; TStack  this, world  s2; TStack  world, world  s3; TStack  world, world  s3;} TStack TNode T s1 is an encapsulated stack with encapsulated elements Client

TStack Example class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head;} class TNode  nodeOwner, TOwner  { TNode  nodeOwner, TOwner  next; TNode  nodeOwner, TOwner  next; T  TOwner  value; T  TOwner  value;} class Client  clientOwner  { TStack  this, this  s1; TStack  this, this  s1; TStack  this, world  s2; TStack  this, world  s2; TStack  world, world  s3; TStack  world, world  s3;} TStack TNode T s2 is an encapsulated stack with public elements Client world

TStack Example class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head;} class TNode  nodeOwner, TOwner  { TNode  nodeOwner, TOwner  next; TNode  nodeOwner, TOwner  next; T  TOwner  value; T  TOwner  value;} class Client  clientOwner  { TStack  this, this  s1; TStack  this, this  s1; TStack  this, world  s2; TStack  this, world  s2; TStack  world, world  s3; TStack  world, world  s3;} TStack TNode T s3 is a public stack with public elements world

TStack Example class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head;} class TNode  nodeOwner, TOwner  { TNode  nodeOwner, TOwner  next; TNode  nodeOwner, TOwner  next; T  TOwner  value; T  TOwner  value;} class Client  clientOwner  { TStack  this, this  s1; TStack  this, this  s1; TStack  this, world  s2; TStack  this, world  s2; TStack  world, world  s3; TStack  world, world  s3; TStack  world, this  s4; // illegal TStack  world, this  s4; // illegal} TStack TNode T Other owners must be same as or more public than first owner [CD02] This constraint is necessary to enforce encapsulation with subtyping

class Client  cOwner, sOwner, tOwner  where (sOwner <= tOwner) { … TStack  sOwner, tOwner  head; TStack  sOwner, tOwner  head;} Constraints on Owners Programmers can constrain owners using where clauses This is legal only if tOwner is same as or more public than sOwner

Iterators Consider an Iterator i over Stack s Consider an Iterator i over Stack s If i is encapsulated within s If i is encapsulated within s  Then i cannot be used outside s If i is not encapsulated within s If i is not encapsulated within s  Then i cannot access representation of s TStack TStackEnum

Solution Use inner classes Use inner classes Gives desired access to representation Gives desired access to representation Yet, satisfies our modularity goal Yet, satisfies our modularity goal

class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head; …. …. class TStackEnum  enumOwner, TOwner  implements class TStackEnum  enumOwner, TOwner  implements TEnum  enumOwner, TOwner  { TEnum  enumOwner, TOwner  { TNode  TStack.this, TOwner  current = TStack.this.head; TNode  TStack.this, TOwner  current = TStack.this.head; …. …. }} Iterators Inner class objects can access rep of outer class objects TStack TStackEnum

class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head; …. …. class TStackEnum  enumOwner, TOwner  implements class TStackEnum  enumOwner, TOwner  implements TEnum  enumOwner, TOwner  {…} TEnum  enumOwner, TOwner  {…} TStackEnum  enumOwner, TOwner  elements  enumOwner  ( ) TStackEnum  enumOwner, TOwner  elements  enumOwner  ( ) where (enumOwner <= TOwner) {…} where (enumOwner <= TOwner) {…}} Iterators TStack TStackEnum

Ownership Types for Encapsulation If an object owns objects it depends on If an object owns objects it depends on Then type system enforces encapsulation Then type system enforces encapsulation  If v is inside s and o is outside  Then o cannot access v  Unless o is inner class object of s v ~ ~ so

class TStack  stackOwner, TOwner  { TNode  this, TOwner  head; TNode  this, TOwner  head; … T  TOwner  pop() writes (this) { T  TOwner  pop() writes (this) { if (head == null) return null; if (head == null) return null; T  TOwner  value = head.value(); T  TOwner  value = head.value(); head = head.next(); head = head.next(); return value; return value; }} Effects Clauses Methods can specify read and write effects reads(x) means method can read x and its encapsulated objects writes(x) means method can read/write x and its encapsulated objects

Related Work Types augmented with owners Types augmented with owners  Clarke, Potter, Noble ( OOPSLA ’98 ) Support for subtyping Support for subtyping  Clarke, Drossopoulou ( OOPSLA ’02 ) Owners combined with effects clauses Owners combined with effects clauses  Boyapati, Rinard ( OOPSLA ’01 )

Summary Ownership types capture dependencies Ownership types capture dependencies Extension for inner class objects allows iterators and wrappers Extension for inner class objects allows iterators and wrappers Approach provides expressive power, yet ensures modular reasoning Approach provides expressive power, yet ensures modular reasoning Effects clauses enhance modular reasoning Effects clauses enhance modular reasoning

Applications Safe upgrades in persistent object stores Safe upgrades in persistent object stores Preventing data races and deadlocks Preventing data races and deadlocks  Boyapati, Lee, Rinard ( OOPSLA ’01 ) ( OOPSLA ’02 ) Safe region-based memory management Safe region-based memory management  Boyapati, Salcianu, Beebee, Rinard ( MIT ’02 ) Program understanding Program understanding  Aldrich, Kostadinov, Chambers ( OOPSLA ’02 )

Upgrades in Persistent Object Stores Persistent Object Stores store objects Persistent Object Stores store objects Persistent Root

Upgrades in Persistent Object Stores Objects are accessed within transactions Objects are accessed within transactions  Transactions support modular reasoning in spite of concurrency and failures Persistent Root

Uses of Upgrades Upgrades are needed to Upgrades are needed to  Correct errors  Improve performance  Meet changing requirements Upgrades can be Upgrades can be  Compatible or incompatible  Upgrades must be complete Encapsulation enables safe upgrades Encapsulation enables safe upgrades

Defining an Upgrade An upgrade is a set of class-upgrades An upgrade is a set of class-upgrades  Upgrades must be complete A class upgrade is A class upgrade is  old-class, new-class, TF   old-class, new-class, TF  TF: old-class  new-class TF: old-class  new-class  TF changes representation of objects  System preserves identity of objects

Executing an Upgrade Requires: transforming all old-class objects Requires: transforming all old-class objects Goal: Don’t interfere with applications Goal: Don’t interfere with applications  Don’t stop the world Goal: Be efficient in space and time Goal: Be efficient in space and time  Don’t copy the database

Solution: Lazy, Just in Time Applications continue to run Applications continue to run Objects are transformed just before first access Objects are transformed just before first access Upgrades can run in parallel Upgrades can run in parallel

Desired Semantics Upgrades appear to run when installed Upgrades appear to run when installed  Serialized before all later application transactions Upgrades appear to run in upgrade order Upgrades appear to run in upgrade order Within an upgrade, transforms run as if each were the first to run Within an upgrade, transforms run as if each were the first to run

Related Work PJama: Atkinson, Dmitriev, Hamilton ( POS ’ 00 ) PJama: Atkinson, Dmitriev, Hamilton ( POS ’ 00 ) Orion: Banerjee, Kim, Kim, Korth ( Sigmod ’ 87 ) Orion: Banerjee, Kim, Kim, Korth ( Sigmod ’ 87 ) O2: Deux et al ( IEEE TKDE ’ 90 ) O2: Deux et al ( IEEE TKDE ’ 90 ) OTGen: Lerner, Habermann ( OOPSLA ’ 90 ) OTGen: Lerner, Habermann ( OOPSLA ’ 90 ) Gemstone: Penney, Stein ( OOPSLA ’ 87 ) Gemstone: Penney, Stein ( OOPSLA ’ 87 )

How System Works Objects are transformed just before first access Objects are transformed just before first access  Interrupt the application  Run earliest pending transform  Transform runs in its owns transaction Application continues after transform commits Application continues after transform commits Transforms can be interrupted too Transforms can be interrupted too

Example …;U1;A1;TF1(x);A2;… U1 is installed A1 commits A2 accesses x and is interrupted TF1(x) commits A2 commits

Example …;U1;A1;TF1(x);A2;… U1 is installed A1 commits A2 accesses x and is interrupted TF1(x) commits A2 commits Suppose A1 modifies z and TF1(x) uses z

Example …;U1;A1;TF1(x);A2;TF1(y);A3; … U1 is installed A1 commits A2 accesses x and is interrupted TF1(x) commits A2 commits A3 accesses y and is interrupted TF1(y) commits A3 commits

Example …;U1;A1;TF1(x);A2;TF1(y);A3; … U1 is installed A1 commits A2 accesses x and is interrupted TF1(x) commits A2 commits A3 accesses y and is interrupted TF1(y) commits A3 commits Suppose TF1(y) uses x

Insuring Correct Behavior S1: TF(x) only accesses objects x owns S1: TF(x) only accesses objects x owns  Statically enforced by type system

Insuring Correct Behavior S1: TF(x) only accesses objects x owns S1: TF(x) only accesses objects x owns  Statically enforced by type system S2: x is transformed before objects x owns S2: x is transformed before objects x owns  No access to owned objects from outside  Shared access to owned objects from inner class objects (e.g., iterator) s v i

Insuring Correct Behavior S1: TF(x) only accesses objects x owns S1: TF(x) only accesses objects x owns S2: x is transformed before objects x owns S2: x is transformed before objects x owns Plus basic lazy scheme Plus basic lazy scheme  Applications don’t interfere with transforms  Transforms of unrelated objects don’t interfere  Transforms of related objects run in proper order (owner before owned)

Modular Reasoning S1: TF(x) only accesses objects x owns S1: TF(x) only accesses objects x owns S2: x is transformed before objects x owns S2: x is transformed before objects x owns Plus basic lazy scheme Plus basic lazy scheme Ensures modular reasoning: can reason about TF(x) as an extra method of x’s class Ensures modular reasoning: can reason about TF(x) as an extra method of x’s class

Conclusions Modular reasoning is key Modular reasoning is key Ownership types support modular reasoning Ownership types support modular reasoning Software upgrades benefit too Software upgrades benefit too

Ownership Types for Object Encapsulation Barbara Liskov Chandrasekhar Boyapati Liuba Shrira Laboratory for Computer Science Massachusetts Institute of Technology {liskov, chandra,

class IntVector { int size() reads (this) {…} … int size() reads (this) {…} …} class IntStack { IntVector  this  vec; IntVector  this  vec; void push(int x) writes (this) {…} … void push(int x) writes (this) {…} …} void m (IntStack s, IntVector v) writes (s) reads (v) where !(v <= s) !(s <= v) { where !(v <= s) !(s <= v) { int n = v.size(); s.push(3); assert( n == v.size() ); int n = v.size(); s.push(3); assert( n == v.size() );} Example of Local Reasoning Is the condition in the assert true?

Example of Local Reasoning s is not encapsulated in v, and v is not encapsulated in s class IntVector { int size() reads (this) {…} … int size() reads (this) {…} …} class IntStack { IntVector  this  vec; IntVector  this  vec; void push(int x) writes (this) {…} … void push(int x) writes (this) {…} …} void m (IntStack s, IntVector v) writes (s) reads (v) where !(v <= s) !(s <= v) { where !(v <= s) !(s <= v) { int n = v.size(); s.push(3); assert( n == v.size() ); int n = v.size(); s.push(3); assert( n == v.size() );}

Example of Local Reasoning size only reads v and its encapsulated objects push only writes s and its encapsulated objects class IntVector { int size() reads (this) {…} … int size() reads (this) {…} …} class IntStack { IntVector  this  vec; IntVector  this  vec; void push(int x) writes (this) {…} … void push(int x) writes (this) {…} …} void m (IntStack s, IntVector v) writes (s) reads (v) where !(v <= s) !(s <= v) { where !(v <= s) !(s <= v) { int n = v.size(); s.push(3); assert( n == v.size() ); int n = v.size(); s.push(3); assert( n == v.size() );}

Example of Local Reasoning So size and push cannot interfere So the condition in the assert must be true class IntVector { int size() reads (this) {…} … int size() reads (this) {…} …} class IntStack { IntVector  this  vec; IntVector  this  vec; void push(int x) writes (this) {…} … void push(int x) writes (this) {…} …} void m (IntStack s, IntVector v) writes (s) reads (v) where !(v <= s) !(s <= v) { where !(v <= s) !(s <= v) { int n = v.size(); s.push(3); assert( n == v.size() ); int n = v.size(); s.push(3); assert( n == v.size() );}