What is immutability and why should I worry about it?

前端 未结 15 981
无人共我
无人共我 2020-12-07 09:51

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

相关标签:
15条回答
  • 2020-12-07 10:28

    What is Immutability?

    • Immutability is applied primarily to objects (strings, arrays, a custom Animal class)
    • Typically, if there is an immutable version of a class, a mutable version is also available. For instance, Objective-C and Cocoa define both an NSString class (immutable) and an NSMutableString class.
    • If an object is immutable, it can't be changed after it is created (basically read-only). You could think of it as "only the constructor can change the object".

    This doesn't directly have anything to do with user input; not even your code can change the value of an immutable object. However, you can always create a new immutable object to replace it. Here's a pseudocode example; note that in many languages you can simply do myString = "hello"; instead of using a constructor as I did below, but I included it for clarity:

    String myString = new ImmutableString("hello");
    myString.appendString(" world"); // Can't do this
    myString.setValue("hello world"); // Can't do this
    myString = new ImmutableString("hello world"); // OK
    

    You mention "an object that just returns information"; this doesn't automatically make it a good candidate for immutability. Immutable objects tend to always return the same value that they were constructed with, so I'm inclined to say the current time wouldn't be ideal since that changes often. However, you could have a MomentOfTime class that is created with a specific timestamp and always returns that one timestamp in the future.

    Benefits of Immutabilty

    • If you pass an object to another function/method, you shouldn't have to worry about whether that object will have the same value after the function returns. For instance:

      String myString = "HeLLo WoRLd";
      String lowercasedString = lowercase(myString);
      print myString + " was converted to " + lowercasedString;
      

      What if the implementation of lowercase() changed myString as it was creating a lowercase version? The third line wouldn't give you the result you wanted. Of course, a good lowercase() function wouldn't do this, but you're guaranteed this fact if myString is immutable. As such, immutable objects can help enforce good object-oriented programming practices.

    • It's easier to make an immutable object thread-safe

    • It potentially simplifies the implementation of the class (nice if you're the one writing the class)

    State

    If you were to take all of an object's instance variables and write down their values on paper, that would be the state of that object at that given moment. The state of the program is the state of all its objects at a given moment. State changes rapidly over time; a program needs to change state in order to continue running.

    Immutable objects, however, have fixed state over time. Once created, the state of an immutable object doesn't change although the state of the program as a whole might. This makes it easier to keep track of what is happening (and see other benefits above).

    0 讨论(0)
  • 2020-12-07 10:29

    Things that are immutable never change. Mutable things can change. Mutable things mutate. Immutable things appear to change but actually create a new mutable thing.

    For example here is a map in Clojure

    (def imap {1 "1" 2 "2"})
    (conj imap [3 "3"])
    (println imap)
    

    The first line creates a new immutable Clojure map. The second line conjoins 3 and "3" to the map. This may appear as if it is modifying the old map but in reality it is returning a new map with 3 "3" added. This is a prime example of immutability. If this had been a mutable map it would have simply added 3 "3" directly to the same old map. The third line prints the map

    {3 "3", 1 "1", 2 "2"}
    

    Immutability helps keep code clean and safe. This and other reasons is why functional programming languages tend to lean towards immutability and less statefulness.

    0 讨论(0)
  • 2020-12-07 10:32

    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
    
    0 讨论(0)
  • 2020-12-07 10:32

    Immutability is about values, and values are about facts. Something has value if is unchangeable, because if something can be changed, then it means that no specific value can be connected to it. Object was initialized with state A and during program execution was mutated to state B and state C. It means that object doesn't represent single specific value but is only a container, abstraction on a place in the memory, nothing more. You can't have trust to such container, you can not believe that this container has the value you suppose should have.

    Let's go to example - lets imagine that in code is created instance of Book class.

    Book bookPotter =  new Book();
    bookPotter.setAuthor('J.K Rowling');
    bookPotter.setTitle('Harry Potter');
    

    This instance has some fields set like author and title. Everything is ok, but in some part of the code again setters are used.

    Book bookLor =  bookPotter; // only reference pass
    bookLor.setAuthor('J.R.R Tolkien');
    bookLor.setTitle('Lords of The Rings');
    

    Don't be cheated by different variable name, really it is the same instance. The code is using setters on the same instance again. It means that bookPotter was never really the Harry Potter book, bookPotter is only pointer to the place where unknown book is located. That said, it looks like it is more a shelf then the book. What trust you can have to such object? It is Harry Potter book or LoR book or neither?

    Mutable instance of a class is only a pointer to an unknown state with the class characteristics.

    How then avoid mutation? It is quite easy in rules:

    • construct object with wanted state via constructor or builder
    • don't create setters for encapsulated state of the object
    • don't change any encapsulated state of the object in any of its methods

    These few rules will allow to have more predictable and more reliable objects. Back to our example and book following above rules:

    Book bookPotter =  new Book('J.K Rowling', 'Harry Potter');
    Book bookLor = new Book('J.R.R Tolkien', 'Lord of The Rings');
    

    Everything is set during constructing phase, in this case constructor, but for bigger structures it can be a builder. No setters exist in objects, book can not mutate to different one. In such case bookPotter represents value of Harry Potter book and you can be sure that this is unchangeable fact.

    If you are interested in wider scope of immutability, in this medium article is more about the subject in relation to JavaScript - https://medium.com/@macsikora/the-state-of-immutability-169d2cd11310.

    0 讨论(0)
  • 2020-12-07 10:33

    You cannot change an immutable object, therefore you must replace it.... "to change it". i.e. replace then discard. "Replacing" in this sense means changing the pointer from one memory location (of the old value) to another (for the new value).

    Note that in doing so we now using additional memory. Some for the old value, some for the new value. Also note, some people get confused because they look at code, such as:

    string mystring = "inital value";
    mystring = "new value";
    System.Console.WriteLine(mystring); // Outputs "new value";
    

    and think to themselves, "but I am changing it, look right there, in black and white! mystring outputs 'new value'...... I thought you said i couldn't change it?!!"

    But actually under the hood, whats happening is this allocation of new memory i.e. mystring is now pointing at a different memory address and space. "Immutable" in this sense, is not referring to the value of mystring but rather the memory used by the variable mystring to store its value.

    In certain languages the memory storing the old value must be manually cleaned up i.e. the programmer must explicitly release it..... and remember to do so. In other languages this is an automatic feature of the language i.e. garbage collection in .Net.

    One of the places this really blows out re:memory usage is in highly iterative loops, specially with strings as in Ashs' post. Say you were building an HTML page in an iterative loop, where you constantly appended the next HTML block to the last and, just for kicks, you were doing this on a high volume server. This constant allocation of "new value memory" can quickly get expensive, and ultimately fatal, if the "old value memory", is not properly cleaned up.

    Another problem is that some people assume things like garbage collection (GC) happens immediately. But it doesn't. There are various optimizations that occur such that garbage collection is set to occur during the more idle periods. So there can be a significant delay between when the memory is marked as discarded and when it is actually freed by the garbage collector.... so you can suffer large memory usage spikes if you simply defer the problem to the GC.

    If the GC doesn't get a chance to operate before you run out of memory, then things wont necessarily fall over like in other languages that don't have automatic garbage collection. Instead the GC will kick in as the highest priority process to free up the discarded memory, no matter how bad the timing, and become a blocking process while it cleans things up. Obviously, this isn't cool.

    So basically, you need to code with these things in mind and look into the documentation for the languages you are using for the best practices/patterns that allow you to avoid/mitigate this risk.

    As in Ashs' post, in .Net and with strings, the recommended practice is to use the mutable StringBuilder class, rather than the immutable string classes when it comes to the need to constantly change a strings value.

    Other languages/types will similarly have their own workarounds.

    0 讨论(0)
  • 2020-12-07 10:35

    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

    0 讨论(0)
自定义标题
段落格式
字体
字号
代码语言
提交回复
热议问题