Javari: Adding Reference Immutability to Java Matthew Tschantz and Michael Ernst MIT CSAIL.
-
date post
22-Dec-2015 -
Category
Documents
-
view
226 -
download
1
Transcript of Javari: Adding Reference Immutability to Java Matthew Tschantz and Michael Ernst MIT CSAIL.
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: finalrd = null; // OK
Date d1 = fd; // OKDate 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 exampleclass Bicycle {
final int id; // Never changes
assignable int hashCode; // A cache
/*this-assign*/ int gear; // Abstract state
}
/*mutable*/ Bicycle b;
readonly Bicycle rb;
finalclass 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
mutable readonly
final unassignable unassignable
assignableclass 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
mutable readonly
final unassignable unassignable
assignable assignable assignable
this-assignableclass 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
mutable readonly
final unassignable unassignable
assignable assignable assignable
this-assignable assignable unassignable
this-assignableclass 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
mutable readonly
final unassignable unassignable
assignable assignable assignable
this-assignable assignable unassignable
Outline
• Language overview– assignability – mutability
• Parametric polymorphism
• Formal model
• Other language features
• Conclusion
MutabilityWhether 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 exampleclass Account { readonly Customer owner; mutable RequestLog requests; /*this-mut*/ Balance bal;}/*mutable*/ Account a;readonly Account ra;
readonlyclass Account { readonly Customer owner; mutable RequestLog requests; /*this-mut*/ Balance bal;}/*mutable*/ Account a;readonly Account ra; a.owner.setName(“Bob”); // Errorra.owner.setName(“Bob”); // Error
Mutability of ref.f
Declared mutability of f
Resolved mutability of ref
mutable readonly
readonly readonly readonly
mutableclass Account { readonly Customer owner; mutable RequestLog requests; /*this-mut*/ Balance bal;}/*mutable*/ Account a;readonly Account ra; a.requests.add(“checkBalance”); // OKra.requests.add(“checkBalance”); // OK
Mutability of ref.f
Declared mutability of f
Resolved mutability of ref
mutable readonly
readonly readonly readonly
mutable mutable mutable
mutable excludes requests from the abstract state of the object
this-mutableclass 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
mutable readonly
readonly readonly readonly
mutable mutable mutable
this-mutable mutable <? readonly>
this-mutableclass Account { readonly Customer owner; mutable RequestLog requests; /*this-mut*/ Balance bal;}/*mutable*/ Account a;readonly Account ra; a.balance.withdraw(1000); // OKra.balance.withdraw(1000); // Error
Mutability of ref.f
Declared mutability of f
Resolved mutability of ref
mutable readonly
readonly readonly readonly
mutable mutable mutable
this-mutable mutable <? readonly>
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-mutableg = 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:<? extends readonly GradeReport super mutable GradeReport>
Notation: <? readonly GradeReport>
Outline
• Language overview– assignability– mutability
• Parametric polymorphism
• Formal model
• Other language features
• Conclusion
Uses of parametric classes
Local variable declarations: /*mut*/ List</*mut*/ Date> a; // add, mutate
/*mut*/ List<readonly Date> b; // add
readonly List</*mut*/ Date> c; // mutate
readonly List<readonly Date> d; // neither
(Arrays are similar)
Inside parametric classesType arguments include mutability
Library cannot write:
class C<T> {
mutable T x;
}
C<readonly Date> y; // Conflicting types
Inside parametric classesType arguments include mutability
Library cannot write:
class C<T> {
mutable T x;
}
C<readonly Date> y; // Conflicting types
Library can force a mutable type using a bound:;
class C<T extends mutable Object> {
T x;
}
this-mutable type arguments
class Wheel { /*this-mut*/ List</*this-mut*/ Spoke> spokes;}
/*mutable*/ Wheel w;readonly Wheel rw;
w.spokes has type /*mut*/ List</*mut*/ Spoke>
/*mut*/ List</*mut*/ Spoke> w = w.spokes; // OK
this-mutable type arguments
class Wheel { /*this-mut*/ List</*this-mut*/ Spoke> spokes;}
/*mutable*/ Wheel w;readonly Wheel rw;
rw.spokes has type ? readonly List<? readonly Spoke>
readonly List<? readonly Spoke> x = rw.spokes; // OK
readonly List<readonly Spoke> y = rw.spokes; // Errorreadonly List</*mutable*/ Spoke> 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