Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'll add to this that it's precisely when values change over time that you want immutability most.

Because when dealing with time, you get a lot of non-determinism when modifying values in variables. This happens because the ordering of non-commutative operations is important, mutable things have identity because their "value" changes with the history of those operations and so with variables and mutable data-structures it gets very hard to reproduce a certain state or to reason about the sequence of events. So in case of errors, it's hard to reproduce a bug or to reason about what ordering you had. Note this isn't to say that operation ordering issues won't happen with immutable data-structures and values - it can happen of course, though having values and pure functions in that chain will make it easier to debug.

But then if you introduce concurrency by multi-threading in the mix, that's when the shit really hits the fan. Because then you have to guarantee a certain ordering and you do that by concurrency primitives, most commonly by intrinsic locks and for one dealing with this stuff is really hard and non-intuitive and also locks are not composable and in general a bottleneck (Amdahl's law ftw). This is why people end up using `Future` and actors and other higher level abstractions for dealing with concurrency, because they make it easier to reason about ordering. But for those that ever worked with Erlang, the "receive" function of actors is meant to be pure, instead of modifying mutable variables, like people normally do in Akka. And in Akka you can work like in Erlang (e.g. context.become), but people rarely do that. And of course, you then get the most horrible mutation known in the software industry, because in addition to having shared mutable state, you're now also dealing with asynchronous message passing on top of that.

As a final word: having the ability to mutate is having power and when mutating variables you're using that power. Sometimes it's necessary, sometimes it's convenient, but many times it's more power than you need. You don't get the luxury of mutability when dealing with accounting for example ;-)



   it's precisely when values change 
   over time that you want immutability 
   most.
Values always change over time, otherwise you could replace variables by constants.

I suggest that immutability is most useful for data that crosses into a context that you (the programmer) have no/little control over. There is nothing wrong with a bit of state, like so

  def pow ( n : Int ) : Int = {
    var result = 1
    var i = n
    while ( i > 0 ) {
      result *= 2
      i -= 1 }
    return result }
The reason this is OK is that the state changes are local, while globally (from the outside) pow remains functional. There is no need to coordinate with other programmers, or other functions or modules, to get i and n to behave properly.

In contrast, if you pass shared state into a context that you have limited knowledge or control over (e.g. shared memory concurrency) then things become hairy.

That's why I advocate: "locally stateful, globally stateless" programming.


Just a note, variables are always replaceable by constants ;-)

   @tailrec
   def pow(n: Int, result: Int = 1): Int =
     if (n > 0) pow(n - 1, result * 2)
     else result
But yes, mutability isn't problematic if it's well encapsulated. Works well for simple functions, but when you get to more complicated things (e.g. classes/modules) the problem is that proper encapsulation is very hard to do, sometimes next to impossible.


Sure, we can always translate away state and pass it explicitly.

Some people find some algorithms can be more naturally expressed using state. (And "some people" is a polite way of saying "alot".) The question of whether state can always be replaced by pure functions without loss of asymptotic complexity is open as of April 2016. All I wanted to point out is that there is no need of becoming a functional Taliban: if state is kept local, that's usually fine.

   when you get to more complicated things
Yes. Then don't use it. My rule of thumb is: definition and all uses of state should be visible to the programmer without scrolling.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: