Immutable object

Immutable object

In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created.[1] This is in contrast to a mutable object, which can be modified after it is created. In some cases, an object is considered immutable even if some internally used attributes change but the object's state appears to be unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.

Immutable objects are often useful because they are inherently thread safe.[1] Other benefits are that they are simpler to understand and reason about and offer higher security than mutable objects.[1]

However, making an object immutable is usually inappropriate if the object contains a large amount of changeable data. Because of this, many languages allow for both immutable and mutable objects.

Contents

Background

Before the advent of OOP, values held in program variables whose content never changed were known as 'constants' to differentiate them from variables that could be altered during execution. Examples might include conversion factors from kilogram weights to pounds or the value of Pi to several decimal places. In most object-oriented languages, objects can be referred to using references. Some examples of such languages are Java, C++, C#, VB.NET, and many scripting languages, such as Python and Ruby. In this case, it matters whether the state of an object can vary when objects are shared via references.

If an object is known to be immutable, it can be copied simply by making a copy of a reference to it instead of copying the entire object. Because a reference (typically only the size of a pointer) is usually much smaller than the object itself, this results in memory savings and a boost in execution speed.

The reference copying 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 the change. If this is not the intended effect, it can be difficult to notify the other users to have them respond correctly. In these situations, defensive copying of the entire object rather than the reference is usually an easy but costly solution. The observer pattern is an alternative technique for handling changes to mutable objects.

Immutable objects can be useful in multi-threaded applications. Multiple threads can act on data represented by immutable objects without concern of the data being changed by other threads. Immutable objects are therefore considered to be more thread-safe than mutable objects.

The practice of always using references in place of copies of equal objects is known as interning. If interning is used, two objects are considered equal if and only if their references, typically represented as integers, are equal. Some languages do this automatically: for example, Python automatically interns short 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 in most applications. (Even if the 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.

Sometimes one talks of certain fields of an object being immutable. This means that there is no way to change those parts of the object state, even though other parts of the object may be changeable. If all fields are immutable then the object is immutable. This might, for example, help to explicitly enforce certain invariants about certain data in the object staying the same through the lifetime of the object. In some languages, this is done with a keyword (e.g. const in C++, final in Java) which designates the field to be immutable. In some languages, it is reversed: in OCaml, fields of an object or record are by default immutable, and need to be explicitly marked with mutable to be mutable.

Implementation

Immutability does not imply that the object as stored in the computer's memory is unwriteable. Rather, immutability is a compile-time construct that indicates what a programmer can do through the normal interface of the object, not necessarily what they can absolutely do (for instance, by circumventing the type system or violating const correctness in C or C++).

Scala

In Scala any variable can be defined as mutable or immutable: simply in the declaration one can use val (value) for immutable objects and var (variable) for mutable ones.

E.g. the following code snippet:

val maxValue = 100
var currentValue = 1

defines an immutable entity maxValue (the integer type is inferred at compile time) and a mutable entity named currentValue.

Actually one should talk about variables only for the mutable objects, and call the immutable entities values or constants.

Java

A classic example of an immutable object is an instance of the Java String class.

String s = "ABC";
s.toLowerCase();

The method toLowerCase() will not change the data "ABC" that s contains. Instead, a new String object is instantiated and given the data "abc" during its construction. A reference to this String object is returned by the toLowerCase() method. To make the String s contain the data "abc", a different approach is needed.

s = s.toLowerCase();

Now the String s references a new String object that contains "abc". There is nothing in the syntax of the declaration of the class String that enforces it as immutable; rather, none of the String class's methods ever affect the data that a String object contains, thus making it immutable.

C++

In C++, a const-correct implementation of Cart would allow the user to declare new instances of the class as either const (immutable) or mutable, as desired, by providing two different versions of the getItems() method. (Notice that in C++ it is not necessary — and in fact impossible — to provide a specialized constructor for const instances.)

template<typename T>
class Cart {
  private:
   std::vector<T> items;
 
  public:
   Cart(const std::vector<T>& v): items(v) { }
 
   std::vector<T>& getItems() { return items; }
   const std::vector<T>& getItems() const { return items; }
   int total() const { /* return sum of the prices */ }
 };

Note that, if there were a field which is a pointer or reference to another object, then it might still be possible to mutate the object pointed to by such a pointer or reference within a const method, without violating const-correctness. It can be argued that in such a case the object is not really immutable.

C++ also provides abstract (as opposed to bitwise) immutability via the mutable keyword, which allows a member variable to be changed from within a const method.

template<typename T>
class Cart {
  private:
   std::vector<T> items;
   mutable int    costInCents;
   mutable bool   totaled;
 
  public:
   Cart(const std::vector<T>& v): items(v), totaled(false) { }
 
   const std::vector<T>& getItems() const { return items; }
   int total() const {
      if (!totaled) {
         costInCents = 0;
         for (std::vector<T>::const_iterator itor = items.begin(); itor != items.end(); ++itor)
            costInCents += itor->costInCents();
 
         totaled = true;
      }
      return costInCents;
   }
 };

Perl

In Perl, creating an immutable class requires two steps: first, creating accessors (either automatically or manually) that prevent modification of object attributes, and secondly, preventing direct modification of the instance data of instances of that class (this is usually stored in a hash reference, and can be locked with Hash::Util's lock_hash function):

package Immutable;
use strict;
use warnings;
use base qw(Class::Accessor);
# create read-only accessors
__PACKAGE__->mk_ro_accessors(qw(value));
use Hash::Util 'lock_hash';
 
sub new {
        my $class = shift;
        return $class if ref($class);
        die "Arguments to new must be key => value pairs\n"
                unless (@_ % 2 == 0);
        my %defaults = (
                value => 'data',
        );
        my $obj = {
                %defaults,
                @_,
        };
        bless $obj, $class;
        # prevent modification of the object data
        lock_hash %$obj;
}
1;

Or, with a manually written constructor:

package Immutable;
use strict;
use warnings;
use Hash::Util 'lock_hash';
 
sub new {
        my $class = shift;
        return $class if ref($class);
        die "Arguments to new must be key => value pairs\n"
                unless (@_ % 2 == 0);
        my %defaults = (
                value => 'data',
        );
        my $obj = {
                %defaults,
                @_,
        };
        bless $obj, $class;
        # prevent modification of the object data
        lock_hash %$obj;
}
 
# read-only accessor
sub value {
        my $self = shift;
        if (my $new_value = shift) {
                # trying to set a new value
                die "This object cannot be modified\n";
        } else {
                return $self->{value}
        }
}
1;

Python

In Python some built-in types (numbers, strings, tuples, frozensets) are immutable, but custom classes are generally mutable. To simulate immutability in a class, one should override attribute setting and deletion to raise exceptions:

class Immutable(object):
     """An immutable class with a single attribute 'value'."""
     def __setattr__(self, *args):
         raise TypeError("can't modify immutable instance")
     __delattr__ = __setattr__
     def __init__(self, value):
         # we can no longer use self.value = value to store the instance data
         # so we must explicitly call the superclass
         super(Immutable, self).__setattr__('value', value)

Racket

Racket substantially diverges from other Scheme implementations by making its core pair type ("cons cells") immutable. Instead, it provides a parallel mutable pair type, via mcons, mcar, set-mcar! etc. In addition, many immutable types are supported, for example, immutable strings and vectors, and these are used extensively. New structs are immutable by default, unless a field is specifically declared mutable, or the whole struct:

(struct foo1 (x y))             ; all fields immutable
(struct foo2 (x [y #:mutable])) ; one mutable field
(struct foo3 (x y) #:mutable)   ; all fields mutable

The language also supports immutable hash tables, implemented functionally, and immutable dictionaries.

Ada

In Ada any object is declared either variable (then, mutable), or constant (then, immutable), with the constant keyword.

  type Some_type is new Integer; -- could be anything more complicated
 
  x: constant Some_type:= 1; -- immutable
  y: Some_type; -- mutable

Subprogram parameters are immutable in the in mode, and mutable in the in out and out modes.

  procedure Do_it(a: in Integer; b: in out Integer; c: out Integer) is
  begin
    -- a is immutable
    b:= b + a;
    c:= a;
  end Do_it;

Copy-on-write

A technique which blends the advantages of mutable and immutable objects, and is supported directly 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 still points to the same object. As soon as a user modifies the object through a particular reference, the system makes a real copy and sets the reference to 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 preserved. Copy-on-write is popular in virtual memory systems because it allows them to save memory space while still correctly handling anything an application program might do.

Usage

Strings and other concrete objects are typically expressed as immutable objects to improve readability and runtime efficiency in object-oriented programming. In Python, Java and the .NET Framework, strings are immutable objects. Both Java and the .NET Framework have mutable versions of string. In Java these are StringBuffer and StringBuilder (mutable versions of Java String) and in .NET this is StringBuilder (mutable version of .Net String). Python 3 has a mutable string (bytes) variant, named bytearray.[1]


Additionally, all of the primitive wrapper classes in Java are immutable.

Enforcement of the pattern can be checked by using specialized compilers (see for example http://pec.dev.java.net/), and there is a proposal to add immutable types to Java.

Similar patterns are the Immutable Interface and Immutable Wrapper.

In pure functional programming languages it is not possible to create mutable objects, so all objects are immutable.

See also

References

This article contains some material from the Perl Design Patterns Book

  1. ^ a b c Goetz et al. Java Concurrency in Practice. Addison Wesley Professional, 2006, Section 3.4. Immutability

External links


Wikimedia Foundation. 2010.

Игры ⚽ Нужен реферат?

Look at other dictionaries:

  • Object (computer science) — In computer science, an object is any entity that can be manipulated by the commands of a programming language, such as a value, variable, function, or data structure. (With the later introduction of object oriented programming the same word,… …   Wikipedia

  • Object type (object-oriented programming) — See also: Object (computer science) In computer science, an object type (a.k.a. wrapping object) is a datatype which is used in object oriented programming to wrap a non object type to make it look like a dynamic object.[citation needed] Some… …   Wikipedia

  • Object lifetime — In computer science, the object lifetime (or life cycle) of an object in object oriented programming is the time between an object s creation (also known as instantiation or construction) till the object is no longer used, and is destructed or… …   Wikipedia

  • Object-relational impedance mismatch — The object relational impedance mismatch is a set of conceptual and technical difficulties that are often encountered when a relational database management system (RDBMS) is being used by a program written in an object oriented programming… …   Wikipedia

  • Object pool pattern — For the article about a general pool see Pool (Computer science) In computer programming, an object pool is a software design pattern. An object pool is a set of initialised objects that are kept ready to use, rather than allocated and destroyed… …   Wikipedia

  • Object type — In computer science, an object type (a.k.a. wrapping object) is a datatype which is used in object oriented programming to wrap a non object type to make it look like a dynamic object.Some object oriented programming languages make a distinction… …   Wikipedia

  • List of object-oriented programming terms — Those words found in object oriented programming. Some are related to OOP and some not. A * Abstract class (also called deferred class) * Abstract method * Abstraction (computer science) * Access control * Accessor method * Allocated class *… …   Wikipedia

  • Constructor (object-oriented programming) — Programming language comparisons General comparison Basic syntax Basic instructions Arrays Associative arrays String operations …   Wikipedia

  • Polymorphism in object-oriented programming — In simple terms, polymorphism is the ability of one type, A, to appear as and be used like another type, B. In strongly typed languages, this usually means that type A somehow derives from type B, or type A implements an interface that represents …   Wikipedia

  • Boundary object — A boundary object is a concept in sociology to describe information used in different ways by different communities. They are plastic, interpreted differently across communities but with enough immutable content to maintain integrity. The ideas… …   Wikipedia

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”