Global mutable data (no matter how frequently mutated) is generally completely incompatible with functional programming. Functional programming is fundamentally about avoiding mutation. From Wikipedia:
Mutable state is usually as limited as it’s feasible to do. In many cases mutable state can live just as long as method invocation making the method (as a whole) functionally pure for an external observer. Look e.g. at scala.List.take method scala/src/library/scala/collection/immutable/List.scala at 6ac6da8b61a3a427089a166c7802a940eac71064 · scala/scala · GitHub :
override def take(n: Int): List[A] = if (isEmpty || n <= 0) Nil else {
val h = new ::(head, Nil)
var t = h
var rest = tail
var i = 1
while ({if (rest.isEmpty) return this; i < n}) {
i += 1
val nx = new ::(rest.head, Nil)
t.tl = nx
t = nx
rest = rest.tail
}
h
}
As you see it uses many variables and even mutates data inside it (in this line: t.tl = nx
), but none of the effects are visible outside of that method. The original List isn’t mutated at all in this method, the resulting List becomes immutable as soon as it’s returned. Variables are reinitialized every time based only on input, not on external mutable state.
I often use Akka actors to manage mutable state. This mutable state can be observed from outside world (well, an actor is mutable anyway, that’s his job to change state), but you cannot modify it directly. Instead, you pass immutable messages to an actor and also receive immutable messages as an answer. This way mutability management is contained within one place and not scattered over potentially entire codebase.