In most OOP languages, objects are generally mutable with a limited set of exceptions (like e.g. tuples and strings in python). In most functional languages, data is immutable.

Both mutable and immutable objects bring a whole list of advantages and disadvantages of their own.

There are languages that try to marry both concepts like e.g. scala where you have (explicitly declared) mutable and immutable data (please correct me if I am wrong, my knowledge of scala is more than limited).

My question is: Does complete (sic!) immutability -i.e. no object can mutate once it has been created- make any sense in an OOP context?

Are there designs or implementations of such a model?

Basically, are (complete) immutability and OOP opposites or orthogonal?

Motivation: In OOP you normally operate on data, changing (mutating) the underlying information, keeping references between those objects. E.g. an object of class Person with a member father referencing another Person object. If you change the name of the father, this is immediately visible to the child object with no need for update. Being immutable you would need to construct new objects for both father and child. But you would have a lot less kerfuffle with shared objects, multi-threading, GIL, etc.

OOP and immutability are almost completely orthogonal to each other. However, imperative programming and immutability are not.

OOP can be summarized by two core features:


Encapsulation: I will not access the contents of objects directly, but rather communicate via a specific interface (“methods”) with this object. This interface can hide internal data from me. Technically, this specific to modular programming rather than OOP. Accessing data via a defined interface is roughly equivalent to an abstract data type.
Dynamic Dispatch: When I call a method on an object, the executed method will be resolved at run time. (E.g. in class-based OOP, I might call a size method on a IList instance, but the call might be resolved to an implementation in a LinkedList class). Dynamic dispatch is one way to allow polymorphic behavior.


Encapsulation makes less sense without mutability (there is no internal state that could be corrupted by external meddling), but it still tends to make abstractions easier even when everything is immutable.

An imperative program consists of statements which are executed sequentially. A statement has side effects like changing the state of the program. With immutability, state cannot be changed (of course, a new state could be created). Therefore, imperative programming is fundamentally incompatible with immutability.

It now happens that OOP has historically always been connected with imperative programming (Simula is based on Algol), and all mainstream OOP languages have imperative roots (C++, Java, C#, … are all rooted in C). This does not imply that OOP itself would be imperative or mutable, this just means that the implementation of OOP by these languages allows mutability.
