Ownership and Immutability in Generic Java (OIGJ)
description
Transcript of Ownership and Immutability in Generic Java (OIGJ)
![Page 1: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/1.jpg)
Ownership and Immutability in Generic Java (OIGJ)
Yoav Zibin, Alex PotaninPaley Li, Mahmood Ali, and Michael D.
Ernst
Presenter: Yossi Gil
![Page 2: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/2.jpg)
2/21
Ownership and Immutability
Owner-as-dominator All reference-chains
from a root to an object pass via its owner
An object cannot leak beyond its owner
No aliases to internal state
Mutable object Fields can be assigned
Immutable object Raw state:
Fields can be assigned Cooked state:
Fields cannot be assigned
ReadOnly references
Ownership Immutability
How can we benefit from a combination?
![Page 3: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/3.jpg)
3/21
Benefits from Ownership + Immutability
Previous work Relaxed owner-as-dominator to owner-as-modifier
ReadOnly references can be freely shared Constrains modification instead of aliasing, i.e., only the owner
can modify an object
OIGJ’s novel idea: Prolong the cooking phase by using ownership
information Makes it easier to create immutable cyclic structures Many objects must be raw simultaneously to create
cyclic structures
![Page 4: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/4.jpg)
4/21
Cooking immutable objects
Previous work An object becomes cooked when its
constructor finishes OIGJ’s observation
An object becomes cooked when its owner’s constructor finishes
The outside world will not see this cooking phase
![Page 5: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/5.jpg)
5/21
Cooking Example: LinkedList
The list owns its entries Therefore, it can mutate them even
after their constructor finished
1: LinkedList(Collection<E> c) {2: this();3: Entry<E> succ = this.header, pred = succ.prev;4: for (E e : c) {5: Entry<E> entry = new Entry<E>(e,succ,pred);6: // It’s illegal to change an entry after it’s cooked.7: pred.next = entry; pred = entry;8: }9: succ.prev = pred;10: }
1: LinkedList(Collection<E> c) {2: this();3: Entry<E> succ = this.header, pred = succ.prev;4: for (E e : c) {5: Entry<E> entry = new Entry<E>(e,succ,pred);6: // It’s illegal to change an entry after it’s cooked.7: pred.next = entry; pred = entry;8: }9: succ.prev = pred;10: }
![Page 6: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/6.jpg)
6/21
Contributions
Formalization Formalized the concepts of raw/cooked objects and
wildcards as owner parameters, and proved soundness
Flexibility OIGJ can type-check more code than previous work:
cyclic structures, the factory and visitor design patterns
No refactoring of existing code Verified that Java’s collection classes are properly
encapsulated (using only 3 ownership annotations) Simplicity
Use generics to express immutability and ownership
![Page 7: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/7.jpg)
7/21
Hierarchies in OIGJ
Immutability hierarchy
ReadOnly – no modification
Raw – object under construction
Ownership hierarchyWorld – anyone can
accessThis – this owns the
object
World
This
ReadOnly
Raw
Mutable
Immut
![Page 8: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/8.jpg)
8/21
OIGJ syntax: fields (1 of 2)
Two new generic parameters were added
1:class Foo<O extends World, I extends ReadOnly> {2: // An immutable reference to an immutable date.
Date<O,Immut> imD = new Date<O,Immut>();3: // A mutable reference to a mutable date.
Date<O,Mutable> mutD = new Date<O,Mutable>();4: // A readonly reference to any date. Both roD and imD cannot mutate // their referent, however the referent of roD might be mutated by an // alias, whereas the referent of imD is immutable.
Date<O,ReadOnly> roD = ... ? imD : mutD;5: // A date with the same owner and immutability as this
Date<O,I> sameD;6: // A date owned by this; it cannot leak.
Date<This,I> ownedD;7: // Anyone can access this date.
Date<World,I> publicD;
1:class Foo<O extends World, I extends ReadOnly> {2: // An immutable reference to an immutable date.
Date<O,Immut> imD = new Date<O,Immut>();3: // A mutable reference to a mutable date.
Date<O,Mutable> mutD = new Date<O,Mutable>();4: // A readonly reference to any date. Both roD and imD cannot mutate // their referent, however the referent of roD might be mutated by an // alias, whereas the referent of imD is immutable.
Date<O,ReadOnly> roD = ... ? imD : mutD;5: // A date with the same owner and immutability as this
Date<O,I> sameD;6: // A date owned by this; it cannot leak.
Date<This,I> ownedD;7: // Anyone can access this date.
Date<World,I> publicD;
![Page 9: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/9.jpg)
9/21
OIGJ syntax: methods (2 of 2)
Method guard <T extends U>? has a dual purpose: The method is included only if T extends U Inside the method, the bound of T is U.
8 : // Can be called on any receiver; cannot mutate this. <I extends ReadOnly>? int readonlyMethod(){...}9 : // Can be called only on mutable receivers; can mutate this. <I extends Mutable>? void mutatingMethod(){...}10: // Constructor that can create (im)mutable objects. <I extends Raw>? Foo(Date<O,I> d) {11: this.sameD = d;12: this.ownedD = new Date<This,I>();13: // Illegal, because sameD came from the outside. // this.sameD.setTime(...);14: // OK, because Raw is transitive for owned fields. this.ownedD.setTime(...);15: }
8 : // Can be called on any receiver; cannot mutate this. <I extends ReadOnly>? int readonlyMethod(){...}9 : // Can be called only on mutable receivers; can mutate this. <I extends Mutable>? void mutatingMethod(){...}10: // Constructor that can create (im)mutable objects. <I extends Raw>? Foo(Date<O,I> d) {11: this.sameD = d;12: this.ownedD = new Date<This,I>();13: // Illegal, because sameD came from the outside. // this.sameD.setTime(...);14: // OK, because Raw is transitive for owned fields. this.ownedD.setTime(...);15: }
![Page 10: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/10.jpg)
10/21
LinkedList Example
1 : class Entry<O,I,E> {2 : E element;3 : Entry<O,I,E> next, prev; …4 : }5 : class LinkedList<O,I,E> {6 : Entry<This,I,E> header; …7 : <I extends Raw>? LinkedList(8 : Collection<?,ReadOnly,E> c) {9 : this(); this.addAll(c);10: }11: <I extends Raw>? void addAll(12: Collection<?,ReadOnly,E> c) {13: Entry<This,I,E> succ = this.header,14: pred = succ.prev;15: for (E e : c) {16: Entry<This,I,E> en =17: new Entry<This,I,E>(e,succ,pred);18: pred.next = en; pred = en; }19: succ.prev = pred;20: }
1 : class Entry<O,I,E> {2 : E element;3 : Entry<O,I,E> next, prev; …4 : }5 : class LinkedList<O,I,E> {6 : Entry<This,I,E> header; …7 : <I extends Raw>? LinkedList(8 : Collection<?,ReadOnly,E> c) {9 : this(); this.addAll(c);10: }11: <I extends Raw>? void addAll(12: Collection<?,ReadOnly,E> c) {13: Entry<This,I,E> succ = this.header,14: pred = succ.prev;15: for (E e : c) {16: Entry<This,I,E> en =17: new Entry<This,I,E>(e,succ,pred);18: pred.next = en; pred = en; }19: succ.prev = pred;20: }
![Page 11: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/11.jpg)
11/21
OIGJ typing rules
Ownership nesting Field access Field assignment Method invocation Method guards Raw parameter
can be used only in method guards (see the paper for all rules, such as
inner classes, covariant subtyping)
![Page 12: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/12.jpg)
12/21
Ownership nesting
List<This, I,Date<World,I>> l1; // Legal nestingList<World,I,Date<This, I>> l2; // Illegal!
List<This, I,Date<World,I>> l1; // Legal nestingList<World,I,Date<This, I>> l2; // Illegal!
The main owner parameter must be inside any other owner parameter.
public static Object<World,ReadOnly> alias_l2;public static Object<World,ReadOnly> alias_l2;
It’s illegal because we can store l2 in this variable:
![Page 13: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/13.jpg)
13/21
Field access/assignment
1: class Foo<O extends World, I extends ReadOnly> {2: Date<This,I> ownedD; // this-owned field3: Date<O,I> sameD;4: <I extends Mutable>? void bar(Foo<This,I> other) {5: this.ownedD = …; // Legal: assign via this6: other.ownedD = …; // Illegal: not via this7: other.sameD = …; // Legal: not this-owned8: }
1: class Foo<O extends World, I extends ReadOnly> {2: Date<This,I> ownedD; // this-owned field3: Date<O,I> sameD;4: <I extends Mutable>? void bar(Foo<This,I> other) {5: this.ownedD = …; // Legal: assign via this6: other.ownedD = …; // Illegal: not via this7: other.sameD = …; // Legal: not this-owned8: }
this-owned fields can be accessed/assigned only via this
![Page 14: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/14.jpg)
14/21
Field assignment
1 : class Foo<O extends World, I extends ReadOnly> {2 : Date<O,I> sameD;3 : <I extends Raw>? void bar(4 : Foo<?,Mutable> mutableFoo,5 : Foo<?,ReadOnly> readonlyFoo,6 : Foo<?,I> rawFoo1,7 : Foo<This,I> rawFoo2) {8 : mutableFoo.sameD = …; // Legal: object is Mutable9 : readonlyFoo.sameD = …; // Illegal: object is not Raw nor Mutable10: rawFoo1.sameD = …; // Illegal: object is not this nor this-owned11: rawFoo2.sameD = …; // Legal: object is Raw and this-owned12: this.sameD = …; // Legal: object is Raw and this13: }
1 : class Foo<O extends World, I extends ReadOnly> {2 : Date<O,I> sameD;3 : <I extends Raw>? void bar(4 : Foo<?,Mutable> mutableFoo,5 : Foo<?,ReadOnly> readonlyFoo,6 : Foo<?,I> rawFoo1,7 : Foo<This,I> rawFoo2) {8 : mutableFoo.sameD = …; // Legal: object is Mutable9 : readonlyFoo.sameD = …; // Illegal: object is not Raw nor Mutable10: rawFoo1.sameD = …; // Illegal: object is not this nor this-owned11: rawFoo2.sameD = …; // Legal: object is Raw and this-owned12: this.sameD = …; // Legal: object is Raw and this13: }
1) A field can be assigned only if the object is Raw or Mutable.
2) If it is Raw, then the object must be this or this-owned.
![Page 15: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/15.jpg)
15/21
Method invocation
1 : class Foo<O extends World, I extends ReadOnly> {2 : Date<This,I> m1() { … } // Parameter is this-owned 3 : <I extends Raw>? void m2() { … }4 : <I extends Raw>? void bar(5 : Foo<?,I> rawFoo1,6 : Foo<This,I> rawFoo2) {7 : this.m1(); // Legal: object is this 8 : rawFoo2.m1(); // Illegal: object is not this9 : rawFoo1.m2(); // Illegal: object is not this nor this-owned10: rawFoo2.m2(); // Legal: both Raw and object is this-owned11: this.m2(); // Legal: both Raw and object is this12: }
1 : class Foo<O extends World, I extends ReadOnly> {2 : Date<This,I> m1() { … } // Parameter is this-owned 3 : <I extends Raw>? void m2() { … }4 : <I extends Raw>? void bar(5 : Foo<?,I> rawFoo1,6 : Foo<This,I> rawFoo2) {7 : this.m1(); // Legal: object is this 8 : rawFoo2.m1(); // Illegal: object is not this9 : rawFoo1.m2(); // Illegal: object is not this nor this-owned10: rawFoo2.m2(); // Legal: both Raw and object is this-owned11: this.m2(); // Legal: both Raw and object is this12: }
Method invocation is the same as field access/assignment:1)If any parameter is this-owned, then the receiver must be this.2)If the guard is Raw and the object is Raw, then the receiver must be this or this-owned.
![Page 16: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/16.jpg)
16/21
Method guards
1: class Foo<O extends World, I extends ReadOnly> {2: <I extends Raw>? void rawM() { … }3: <I extends Mutable>? void bar(4: Foo<?,ReadOnly> readonlyFoo,5: Foo<?,I> mutableFoo) {6: readonlyFoo.rawM(); // Illegal: ReadOnly is not a subtype of Raw // The bound of I in this method is Mutable7: mutableFoo.rawM(); // Legal: Mutable is a subtype of Raw8: this.rawM(); // Legal: Mutable is a subtype of Raw9: }
1: class Foo<O extends World, I extends ReadOnly> {2: <I extends Raw>? void rawM() { … }3: <I extends Mutable>? void bar(4: Foo<?,ReadOnly> readonlyFoo,5: Foo<?,I> mutableFoo) {6: readonlyFoo.rawM(); // Illegal: ReadOnly is not a subtype of Raw // The bound of I in this method is Mutable7: mutableFoo.rawM(); // Legal: Mutable is a subtype of Raw8: this.rawM(); // Legal: Mutable is a subtype of Raw9: }
Guard “<T extends U>?” has a dual purpose:1)The receiver’s T must be a subtype of U.2)Inside the method, the bound of T is U.
Conditional Java (cJ) proposed method guards for Java
![Page 17: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/17.jpg)
17/21
Formalization: Featherweight OIGJ
Novel idea: CookersEvery location l in the heap is of the form:
l' is the owner of ll” is the cooker of l, i.e., when the
constructor of l” finishes then l becomes cooked
We keep track of the set of ongoing constructors
Subtyping rules connect cookers and owners
lFoo<l’,Immut >lFoo<l’,Mutable> or l"
Proved soundness and type preservation
![Page 18: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/18.jpg)
18/21
Case studies
From Generics to AnnotationsDate<O,I> @OI Date
Implementation uses the checkers frameworkOnly 1600 lines of code (but still a
prototype)Requires type annotations available in
Java 7 Java’s Collections case study
77 classes, 33K lines of code85 ownership-related annotations46 immutability-related annotations
![Page 19: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/19.jpg)
19/21
Case studies conclusions
Verified that collections own their representation
Method get must be Mutable! new LinkedHashMap(100, 1, /*accessOrder=*/ true)
Order of iteration is the order in which its entries were last accessed
Method overriding can only make the guard less strict
Method clone is problematicClone makes a shallow copy that breaks
ownershipOur suggestion: compiler-generated clone that
nullifies fields, and then calls a copy-constructor
![Page 20: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/20.jpg)
20/21
Conclusions
Ownership Immutability Generic Java (OIGJ)Simple, intuitive, smallStatic – no runtime penalties (like
generics)Backward compatible, no JVM changesHigh degree of polymorphism using
generics and safe covariant subtypingCase study proving usefulnessFormal proof of soundness
![Page 21: Ownership and Immutability in Generic Java (OIGJ)](https://reader036.fdocuments.us/reader036/viewer/2022070410/56814583550346895db263a5/html5/thumbnails/21.jpg)
21/21
Future work
Inferring ownership and immutability annotations
Bigger case study Extending OIGJ
owner-as-modifier uniqueness or external uniqueness
Questions?