Immutable object
|
In computer science, an immutable object, as opposed to a mutable object, is a kind of object whose internal states cannot be modified after it was created. An object can be immutable as whole or some attributes in the object may be immutable, as in C++'s const member data attribute. In some cases, an object is considered immutable while some attributes for internal use change (like for caching purpose) yet the state appears to be unchanging. The initial state of an immutable object is mostly set at its inception, but it can be set right before actual use of the object.
Immutable objects are often useful because when an object is known to be immutable, some of costly operations for copying and comparing may be omitted altogether, simplyfing the program code and speeding up its execution. Since sometimes making an object immutable costs in time and space, the use of immutable objects may not result in improvement. This is especially so when an object contains a large amount of data. Because of this, many languages allow for both immutable and mutable versions of objects.
Contents |
Background
In some languages, objects are handled as a reference rather than a concrete value. Many OOP languages take that scheme, including Java. In that case, it matters whether the state of object can vary or not since objects are shared via references.
If an object is known to be immutable, then instead of creating copies of the entire object, only copies to a reference to it need be made. Because a reference is very often much smaller than the object itself (typically only the size of a pointer), this results in savings of memory usage and boost in execution speed.
This technique is much more difficult to use for mutable objects, because if any user of a reference to a mutable object changes it, all other users of that reference will see that change. If this is not the intended effect, it can be difficult to notify the other users to have them respond correctly. In such situations, copying of the entire object rather than the reference, known as defensive copy, is usually the easiest yet potentially costly solution. For a well-known technique that handles changes to mutable objects, see the discussion on the observer pattern.
The attempt to comprehensively use references in place of copies of equal objects is known as interning. Some languages do this automatically; for example, Python automatically interns strings. If the algorithm which implements interning is guaranteed to do so in every case that it is possible, then comparing objects for equality is reduced to comparing their pointers, a substantial gain in speed for some applications. (Even if that algorithm is not guaranteed to be comprehensive, there still exists the possibility of a fast path case improvement when the objects are equal and use the same reference.) Interning is generally only useful for immutable objects.
The immutable pattern is typically most useful in multi-threaded applications. This is because when an operation is to be executed against a piece of data that an Immutable Object represents then another thread can act on that same data without fear of it changing during its operation.
Implementation
A technique which blends the advantages of mutable and immutable objects, and supported in almost all modern hardware, is copy-on-write (COW). Using this technique, when a user asks the system to copy an object, it will instead merely create a new reference which, through hardware trickery, still points to that same object. As soon as a user modifies the object through a particular reference, a real copy is made by the system and that same reference will now refer to the new copy. The other users are unaffected, because they still refer to the original object. Therefore, under COW, all users appear to have a mutable version of their objects, although in the case that users do not modify their objects, the space-saving and speed advantages of immutable objects are retained. COW is popular in virtual memory systems because it allows them to save memory space in the core while still correctly handling anything an application program might do.
Example
For an object to be immutable, there has to be no way to change fields, mutable or not, and to access fields that are mutable. For example,
class Cart { private final List items; public Cart (List items) { this.items = items; } public List getItems () { return items; } public int total () { ... /* return sum of the prices */ } }
An object as an instance of this class is not immutable; one can add or remove items either by obtaining a field items
by calling getItems ()
or retaining a list object passed when an object of this class is created. The following, for one, mitigates this problem; thus, an object would be immutable.
class Cart { private final List items; public Cart (List items) { this.items = Arrays.asList (items.toArray ()); } public List getItems () { return Collections.unmodifiableList (items); } public int total () { ... /* return sum of the prices */ } }
Usage
Strings or other concrete objects are typically expressed as immutable object to improve readability and runtime efficiency in object-oriented programming. In Python and Java, strings are immutable objects. Java has a class StringBuffer, which is a mutable object in addition to the immutable java.lang.String.
Other immutable classes in Java are Byte, Character, Short, Integer, Long, Float and Double.
Example in Java
A perfect example is the Java String object.
String abc = "ABC"; abc.toLower();
The method toLower()
will have no impact on the data "ABC", that abc
contains. What happens is that a new String object is instantiated and given the data "abc" during its construction. The returned String object will always refer to the string "abc". So to make the String identifier abc
contain the data "abc" the following needs to be done :
abc = abc.toLower();
Now the identifier abc
references a new String object that contains "abc". The String object's method never affects the data the String object contains, excluding the constructor. In Java, this policy can be enforced by defining the data final
during construction.
The pattern can be enforced using a Pattern Enforcing Compiler (PEC(TM)) (http://pec.dev.java.net/) and there is a proposal (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4617197) to add immutable types to Java.
Similar patterns are Immutable Interface and the Immutable Wrapper.
External links
- Article "Pattern: Immutable Object (http://www.doc.ic.ac.uk/~np2/patterns/concurrency/immutable-object.html)" by Nat Pryce
- Article "Java theory and practice: To mutate or not to mutate? (http://www-106.ibm.com/developerworks/java/library/j-jtp02183.html)" by Brian Goetz
- Article "Immutable objects (http://www.topcoder.com/index?t=features&c=feat_071003)" by vorthys on "Topcoder.com (http://www.topcoder.com)"
- Java Reference Java Practices: Immutable objects (http://www.javapractices.com/Topic29.cjp)
- Descriptions from Portland Pattern Repository (http://c2.com/cgi/wiki?ImmutableObject)
- Chapter "Immutability of Objects (http://www.stud.uni-karlsruhe.de/~unk6/clim-spec/2-4.html)" in the Common Lisp Interface Manager Specification
- Chapter "Immutable Classes (http://swt.cs.tu-berlin.de/~stephan/OOPL/Sather-Chap4-12.html#MARKER-9-135)" from a Sather manual
The article contains materials partly from Perl Design Patterns Book.