top | item 20948836

(no title)

siempreb | 6 years ago

There is something about this immutability thing I really don't like. In the authors example it looks like v1[0] is set to 42 (const auto v2 = v1.set(0, 42)), at least that's how you read it because it contains the word 'set', but you have to 'know' that v1 is immutable and is actually not setting the value, but returning it. So IMAO the naming should be better, I like to read code that is not confusing.

If this construct, that I actually never needed in my entire career, is handy for undo/redo, why not just have a dead simple undo stack? In what situation is an immutable structure your best choice?

discuss

order

maemre|6 years ago

They are pretty useful for certain kinds of program analysis (like abstract interpretation and symbolic execution) where you need to create slightly modified copies of the program state (e.g. when you need to split the state on a conditional, or merge two states). Immutable data structures are (space) efficient for this use case. Moreover, you can combine them with hash consing for more space efficiency (only if you are creating lots of objects that share most of their data) and fast equality checking where there is only one copy a value in heap so equality checking is just object identity checking and addresses work as hash values now so hashing large objects is faster too.

The algorithms used in these analyses are usually described in terms of mathematical objects which are inherently immutable and using immutable objects makes correctness proofs easier.

When writing a piece of code, I start with immutable data structures because of the ease of mind they bring to the table (you can pass them around and you know they will not be modified so it makes reasoning and debugging easier, this is less of a problem in C++ because it has const references and const methods). Then, if an algorithm needs a mutable data structure or if the immutable data structures are too slow (e.g. the code is in the hot path) then I switch to mutable data structures. I think it is just a different mentality when approaching programming. It works for me because (a) it is the norm in my field (program analysis, or programming languages in general), and (b) I use a programming language with an ecosystem around immutable data structures (Scala).

siempreb|6 years ago

Thank you all for taking the time to explain, very valuable for me at least.

hokkos|6 years ago

I see no problem with the set method name, this is what is used in other lib in other languages. When you use an immutable lib you understand the meaning and that every operation create a new base object.

This is extremely useful for undo/redo, it basically comes for free with it. You no longer have to deal with invisible mutation, listener, event, you just generate the ui on each change from the base to the leaf, and everything is always correct for free. The advantage over an undo stack is that there is a re-utilization of unchanged intermediate data structure (what is change is only the path from the base to the changed element), so you can add a simple ref check in the ui to not redraw of the underlying data has not changed. So the perf come for free.

dfgdghdf|6 years ago

The simplest answer is that immutability allows you to share data around without worrying about it being modified.

In the OOP world, you might have a "getter" for a property (e.g. a list of some kind) that you don't want readers to be able to modify.

Perhaps "set" was a poor name here, since it usually means something else in a C++ context. I quite like "with".

dfgdghdf|6 years ago

Should add that C++ has const, making some of this irrelevant. In the C++ case immutability is about making minor changes to a structure more efficient by reusing the previous version. This is only possible with immutability because you need to be sure that your "base" structure won't change underneath you!

physicsyogi|6 years ago

Persistent data structures are thread-safe and are useful for concurrency. That's partly why they are a core part of functional programming languages like Clojure and Haskell. Persistent data structures are also useful for version control.

bjoli|6 years ago

In scheme, mutating functions end with "!". (append lst lst2) creates a new list without modifying lst, whereas (append! ...) is allowed, but not necessarily required, to mutate the list.

agumonkey|6 years ago

what would be a good word for this ? recreate ? recompute ? with_new ?

ScottBurson|6 years ago

In general, I think verbs should be avoided, when possible, as names of functional operations. For instance, in Java, 'BigInteger.add' should have been 'plus'. Compare:

  x.add(y);
  x.plus(y);
People have been known to write the first one expecting 'x' to be updated. With the second, I think it's clearer that it's a value that needs to be assigned to a variable.

For the operation in question here, I suggest 'with'. This is what I have used in my own functional collections libraries; I think it originated in SETL.

masklinn|6 years ago

Clojure as `(assoc col key val)` and `(update col key fn)` though I don't know that the naming scheme is significantly clearer.