What is immutability and why should I worry about

2019-01-16 03:01发布

I've read a couple of articles on immutability but still don't follow the concept very well.

I made a thread on here recently which mentioned immutability, but as this is a topic in itself, I am making a dedicated thread now.

I mentioned in the past thread that I thought immutability is the process of making an object read only and giving it low visibility. Another member said it didn't really have anything to do with that. This page (part of a series) uses an example of an immutable class/struct and it uses readonly and other concepts to lock it down.

What exactly is the definition of state in the case of this example? State is a concept which I haven't really grasped.

From a design guideline perspective, an immutable class must be one which does not accept user input and really would just return values?

My understanding is that any object which just returns information should be immutable and "locked down", right? So if I want to return the current time in a dedicated class with that one method, I should use a reference type as that will work a reference of the type and thus I benefit from immutability.

15条回答
看我几分像从前
2楼-- · 2019-01-16 03:15

Sorry, why does immutability prevent race conditions (in this example, write after read hazards)?

shared v = Integer(3)
v = Integer(v.value() + 1) # in parallel
查看更多
虎瘦雄心在
3楼-- · 2019-01-16 03:20

Immutability

Simply put, memory is immutable when it is not modified after being initialised.

Programs written in imperative languages such as C, Java and C# may manipulate in-memory data at will. An area of physical memory, once set aside, may be modified in whole or part by a thread of execution at any time during the program's execution. In fact, imperative languages encourage this way of programming.

Writing programs in this way has been incredibly successful for single-threaded applications. However as modern application development moves towards multiple concurrent threads of operation within a single process, a world of potential problems and complexity is introduced.

When there is only one thread of execution, you can imagine that this single thread 'owns' all of the data in memory, and so therefore can manipulate it at will. However, there is no implicit concept of ownership when multiple executing threads are involved.

Instead, this burden falls upon the programmer who must go to great pains to ensure that in-memory structures are in a consistent state for all readers. Locking constructs must be used in careful measure to prohibit one thread from seeing data while it is being updated by another thread. Without this coordination, a thread would inevitably consume data that was only halfway through being updated. The outcome from such a situation is unpredictable and often catastrophic. Furthermore, making locking work correctly in code is notoriously difficult and when done badly can cripple performance or, in the worst case, case deadlocks that halt execution irrecoverably.

Using immutable data structures alleviates the need to introduce complex locking into code. When a section of memory is guaranteed not to change during the lifetime of a program then multiple readers may access the memory simultaneously. It is not possible for them to observe that particular data in an inconsistent state.

Many functional programming languages, such as Lisp, Haskell, Erlang, F# and Clojure, encourage immutable data structures by their very nature. It is for this reason that they are enjoying a resurgence of interest as we move towards increasingly complex multi-threaded application development and many-computer computer architectures.

State

The state of an application can simply be thought of as the contents of all the memory and CPU registers at a given point in time.

Logically, a program's state can be divided into two:

  1. The state of the heap
  2. The state of the stack of each executing thread

In managed environments such as C# and Java, one thread cannot access the memory of another. Therefore, each thread 'owns' the state of its stack. The stack can be thought of as holding local variables and parameters of value type (struct), and the references to objects. These values are isolated from outside threads.

However, data on the heap is shareable amongst all threads, hence care must be taken to control concurrent access. All reference-type (class) object instances are stored on the heap.

In OOP, the state of an instance of a class is determined by its fields. These fields are stored on the heap and so are accessible from all threads. If a class defines methods that allow fields to be modified after the constructor completes, then the class is mutable (not immutable). If the fields cannot be changed in any way, then the type is immutable. It is important to note that a class with all C# readonly/Java final fields is not necessarily immutable. These constructs ensure the reference cannot change, but not the referenced object. For example, a field may have an unchangeable reference to a list of objects, but the actual content of the list may be modified at any time.

By defining a type as being truly immutable, its state can be considered frozen and therefore the type is safe for access by multiple threads.

In practice, it can be inconvenient to define all of your types as immutable. To modify the a value on an immutable type can involve a fair bit of memory copying. Some languages make this process easier than others, but either way the CPU will end up doing some extra work. Many factors contribute to determine whether the time spent copying memory outweighs the impact of locking contentions.

A lot of research has gone into the development of immutable data structures such as lists and trees. When using such structures, say a list, the 'add' operation will return a reference to a new list with the new item added. References to the previous list do not see any change and still have a consistent view of the data.

查看更多
Evening l夕情丶
4楼-- · 2019-01-16 03:25

"... why should I worry about it?"

A practical example is repetitive concatenation of strings. In .NET for example:

string SlowStringAppend(string [] files)
{
    // Declare an string
    string result="";

    for (int i=0;i<files.length;i++)
    {
        // result is a completely new string equal to itself plus the content of the new
        // file
        result = result + File.ReadAllText(files[i]);
    }

    return result;
}    

string EfficientStringAppend(string [] files)
{
    // Stringbuilder manages a internal data buffer that will only be expanded when absolutely necessary
    StringBuilder result=new SringBuilder();

    for (int i=0;i<files.length;i++)
    {
        // The pre-allocated buffer (result) is appended to with the new string 
        // and only expands when necessary.  It doubles in size each expansion
        // so need for allocations become less common as it grows in size. 
        result.Append(File.ReadAllText(files[i]));
    }

    return result.ToString();
}

Unfortunately using the first (slow) function approach is still commonly used. An understanding of immutability makes it very clear why using StringBuilder is so important.

查看更多
放我归山
5楼-- · 2019-01-16 03:26

Good question.

Multi-threading. If all types are immutable then race conditions don't exist and you're safe to throw as many threads at the code as you wish.

Obviously you can't accomplish that much without mutability save complex calculations so you usually need some mutability to create functional business software. However it is worth recognising where immutability should lie such as anything transactional.

Look up functional programming and the concept of purity for more information on the philosophy. The more you store on the call stack (the params you're passing to methods) as opposed to making them available via references such as collections or statically available objects the more pure your program is and the less prone to race conditions you will be. With more multi-cores these days this topic is more important.

Also immutability reduces the amount of possibilities in the program which reduces potential complexity and potential for bugs.

查看更多
叛逆
6楼-- · 2019-01-16 03:26

Why Immutability?

  1. They are less prone to error and are more secure.

  2. Immutable classes are easier to design, implement, and use than mutable classes.

  3. Immutable objects are thread-safe so there is no synchronization issues.

  4. Immutable objects are good Map keys and Set elements, since these typically do not change once created.

  5. Immutability makes it easier to write, use and reason about the code (class invariant is established once and then unchanged).

  6. Immutability makes it easier to parallelize program as there are no conflicts among objects.

  7. The internal state of program will be consistent even if you have exceptions.

  8. References to immutable objects can be cached as they are not going to change.(i.e in Hashing it provide fast operations).

See my blog for a more detailed answer:
http://javaexplorer03.blogspot.in/2015/07/minimize-mutability.html

查看更多
该账号已被封号
7楼-- · 2019-01-16 03:27

Look, I haven't read the links that you have posted.

However, here is my understanding.
Every program holds some knowledge of it's data (State), which can change either by user-input/external changes etc.

Variables (values which change) are kept to maintain state. Immutable means some data which doesn't change. You can say, it is same as readonly or constant in some way (it can be seen it that way).

AFAIK, functional programming has things immutable (i.e. you cannot use assignment to a variable holding the value. What you can do is create another variable which can hold the original value + changes).

.net has string class which is an example.
i.e. You can't modify string in its place

string s = "hello"; I can write s.Replace("el", "a"); But this won't modify the contents of variable s.

What I can do is s = s.Replace("el","a");
This will create a new variable & assign its value to s (overwriting content of s).

Experts can correct mistakes if I have, in my understanding.

EDIT: Immutable = Unassignable once it is holding some value & can't be replaced in place (maybe?)

查看更多
登录 后发表回答