Javari: Adding Reference Immutability to Java Matthew Tschantz and Michael Ernst MIT CSAIL
Protecting method arguments static void print(readonly Date d) {... // Cannot modify d } String toString() readonly {... // Cannot modify the receiver }
Protecting abstract state: observer methods class Class { private Object[] signers; readonly Object[] getSigners() { return signers; // JDK 1.1 bug } myClass.getSigners()[0] = “Sun”;
Protecting abstract state: observer methods class Class { private Object[] signers; readonly Object[] getSigners() { return signers; // Fixes JDK 1.1 bug } myClass.getSigners()[0] = “Sun”; // Error
Reference immutability A given reference cannot be used to modify its referent –other references to the object may modify it Is deep: the transitively reachable state (the abstract state) is protected Statically type checkable
Reference immutability versus object immutability Object immutability: an object cannot be modified through any reference Graph temp = new Graph(); // construct the graph readonly Graph g = temp; temp = null;
Motivation Provide compiler-enforced guarantees that a method will not change a given parameter Protect an object’s abstract state Prevent/detect errors Documentation Enable analyses and transformations
Other work C++: –unsound (unchecked casts) –non-transitive –no parametric polymorphism JAC [Kniesel 2001]: –unsound (subtyping, arrays) –return type mutability equals receiver's Javari2004 [Birka 2004]: –no parametric polymorphism –conflates assignability and mutability Object immutability –restricts programmer
Outline Language overview –assignability –mutability Parametric polymorphism Formal model Other language features Conclusion
Language overview readonly Immutable reference assignable Field may be reassigned even through a read-only reference mutable Field may be mutated even through a read-only reference
Readonly readonly Date rd = new Date(); rd.year = 2005; // Compile-time error rd.incrementDay(); // Compile-time error rd = new Foo(); // OK
Mutability versus assignability Mutability –part of the type –readonly final Date fd = null; readonly Date rd = null; fd = new Date(); // Error: final rd = null; // OK Date d1 = fd; // OK Date d2 = rd; // Error: wrong type Assignability –not part of the type –final
Type system Every type (mutable) T has readonly T as a supertype readonly Object readonly Date /*mutable*/ Object /*mutable*/ Date
Outline Language overview –assignability –mutability Parametric polymorphism Formal model Other language features Conclusion
Assignability Whether a reference may be assigned to. class Appointment { final Date time; // Same as in Java assignable int room; } Appointment appoint; appoint.time = new Date(); // Error appoint.room = 250; // OK
Assignability modifiers final: May never be assigned assignable: May always be assigned; the default for locals this-assignable: –May be assigned through a mutable reference –May not be assigned through a readonly reference –Only applicable to fields; the default –The assignability depends on the mutability of the enclosing object: “this”
Assignability example class Bicycle { final int id; // Never changes assignable int hashCode; // A cache /*this-assign*/ int gear; // Abstract state } /*mutable*/ Bicycle b; readonly Bicycle rb;
final class Bicycle { final int id; // Never changes assignable int hashCode; // A cache /*this-assign*/ int gear; // Abstract state } /*mutable*/ Bicycle b; readonly Bicycle rb; b.id = 5; // Error rb.id = 5; // Error Resolved assignability of ref.f Declared assignability of f Resolved mutability of ref mutablereadonly finalunassignable
assignable class Bicycle { final int id; // Never changes assignable int hashCode; // A cache /*this-assign*/ int gear; // Abstract state } /*mutable*/ Bicycle b; readonly Bicycle rb; b.hashCode = 5; // OK rb.hashCode = 5; // OK Resolved assignability of ref.f Declared assignability of f Resolved mutability of ref mutablereadonly finalunassignable assignable
this-assignable class Bicycle { final int id; // Never changes assignable int hashCode; // A cache /*this-assign*/ int gear; // Abstract state } /*mutable*/ Bicycle b; readonly Bicycle rb; b.gear = 5; // OK Resolved assignability of ref.f Declared assignability of f Resolved mutability of ref mutablereadonly finalunassignable assignable this-assignableassignableunassignable
this-assignable class Bicycle { final int id; // Never changes assignable int hashCode; // A cache /*this-assign*/ int gear; // Abstract state } /*mutable*/ Bicycle b; readonly Bicycle rb; b.gear = 5; // OK rb.gear = 5; // Error Resolved assignability of ref.f Declared assignability of f Resolved mutability of ref mutablereadonly finalunassignable assignable this-assignableassignableunassignable
Outline Language overview –assignability –mutability Parametric polymorphism Formal model Other language features Conclusion
Mutability Whether an object’s transitive abstract state may be modified class Date { /*this-assignable*/ int year; } /*mutable*/ Date d; readonly Date rd; d.year = 2005; // OK rd.year = 2005; // Error
Mutability modifiers readonly: May never be mutated mutable: May always be mutated; the default for locals this-mutable: –May be mutated through mutable reference –May not be mutated through readonly references –Only applicable to fields; the default –The mutability depends on the mutability of the enclosing class: “this”
Mutability example class Account { readonly Customer owner; mutable RequestLog requests; /*this-mut*/ Balance bal; } /*mutable*/ Account a; readonly Account ra;
readonly class Account { readonly Customer owner; mutable RequestLog requests; /*this-mut*/ Balance bal; } /*mutable*/ Account a; readonly Account ra; a.owner.setName(“Bob”); // Error ra.owner.setName(“Bob”); // Error Mutability of ref.f Declared mutability of f Resolved mutability of ref mutablereadonly
mutable class Account { readonly Customer owner; mutable RequestLog requests; /*this-mut*/ Balance bal; } /*mutable*/ Account a; readonly Account ra; a.requests.add(“checkBalance”); // OK ra.requests.add(“checkBalance”); // OK Mutability of ref.f Declared mutability of f Resolved mutability of ref mutablereadonly mutable mutable excludes requests from the abstract state of the object
this-mutable class Account { readonly Customer owner; mutable RequestLog requests; /*this-mut*/ Balance bal; } /*mutable*/ Account a; readonly Account ra; a.balance.withdraw(1000); // OK Mutability of ref.f Declared mutability of f Resolved mutability of ref mutablereadonly mutable this-mutablemutable
this-mutable class Account { readonly Customer owner; mutable RequestLog requests; /*this-mut*/ Balance bal; } /*mutable*/ Account a; readonly Account ra; a.balance.withdraw(1000); // OK ra.balance.withdraw(1000); // Error Mutability of ref.f Declared mutability of f Resolved mutability of ref mutablereadonly mutable this-mutablemutable
this-mutable fields reached through a readonly reference readonly, right?
this-mutable fields reached through a readonly reference readonly, right? NO, would result in type loophole allowing one to convert a readonly reference to a mutable reference:
this-mutable fields reached through a readonly reference readonly, right? NO, would result in type loophole allowing one to convert a readonly reference to a mutable reference: class Student { assignable /*this-mut*/ GradeReport grades; } /*mutable*/ Student s = new Student(); readonly Student rs = s; readonly GradeReport rg; /*mutable*/ GradeReport g; rs.grades = rg; //readonly assigned to this-mutable g = s.grades; //this-mutable assigned to mutable
this-mutable fields reached through a readonly reference Solution: Disallow readonly references to be assigned to a this- mutable field class Student { assignable /*this-mut*/ GradeReport grades; } this-mutable fields are taken out at readonly GradeReport written to as mutable GradeReport
this-mutable fields reached through a readonly reference Solution: Disallow readonly references to be assigned to a this- mutable field class Student { assignable /*this-mut*/ GradeReport grades; } this-mutable fields are taken out at readonly GradeReport written to as mutable GradeReport Using wildcards and bounds, the type of grades can be written as: Notation:
Outline Language overview –assignability –mutability Parametric polymorphism Formal model Other language features Conclusion
Uses of parametric classes Local variable declarations: /*mut*/ List a; // add, mutate /*mut*/ List b; // add readonly List c; // mutate readonly List d; // neither (Arrays are similar)
Inside parametric classes Type arguments include mutability Library cannot write: class C { mutable T x; } C y; // Conflicting types
Inside parametric classes Type arguments include mutability Library cannot write: class C { mutable T x; } C y; // Conflicting types Library can force a mutable type using a bound: ; class C { T x; }
this-mutable type arguments class Wheel { /*this-mut*/ List spokes; } /*mutable*/ Wheel w; readonly Wheel rw; w.spokes has type /*mut*/ List /*mut*/ List w = w.spokes; // OK
this-mutable type arguments class Wheel { /*this-mut*/ List spokes; } /*mutable*/ Wheel w; readonly Wheel rw; rw.spokes has type ? readonly List readonly List x = rw.spokes; // OK readonly List y = rw.spokes; // Error readonly List z = rw.spokes; // Error
Outline Language overview –assignability –mutability Parametric polymorphism Formal model Other language features Conclusion
Formal model Core language Extension to Featherweight Generic Java Type soundness proof underway –Subject reduction and progress theorems Proof that an object is never modified if only a readonly reference exists
Outline Language overview –assignability –mutability Parametric polymorphism Formal model Other language features Conclusion
Reflection Method.invoke continues to return mutable references –dynamically checks type signature: return type must be mutable New method Method.invokeReadonly returns a readonly reference –no dynamic checks Type, including mutability, of arguments (including receiver) is checked at compile time.
Serialization Add a readonly-ness bit to the serialized form. Check readonly-ness bit if one attempts to deserialization an object to a mutable reference.
Reducing code duplication romaybe keyword templates over methods class Conference { /*this-mutable*/ Date d; We wish to write two (overloaded) methods: readonly Date getDate() readonly { return d; } /*mutable*/ Date getDate() /*mutable*/ { return d; } Syntactic sugar: romaybe Date getDate() romaybe { return d; } }
Outline Language overview –assignability –mutability Parametric polymorphism Formal model Other language features Conclusion
Contributions Transitive reference immutability Distinguishes assignability and mutability Formal model Type system for full Java including parametric polymorphism, reflection, and serialization Templates to reduce code duplication Interoperable with Java