Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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.

share|improve this question
2  
Immutability can be simulated in an OOP language, by only exposing object access points as methods or read-only properties that do not mutate the data. Immutability works the same in OOP languages as it does in any functional language, except that you may be missing some functional language features. –  Robert Harvey Mar 17 at 19:12
1  
Mutability is not a property of OOP languages like C# and Java, nor is immutability. You specify mutability or immutability by the way you write the class. –  Robert Harvey Mar 17 at 19:17
5  
Your presumption seems to be that mutability is a core feature of object-orientation. It isn't. Mutability is simply a property of objects or values. Object-orientation encompasses a number of intrinsic concepts (encapsulation, polymorphism, inheritance, etc.) that have little or nothing to do with mutation, and you would still derive the benefits of those features. even if you made everything immutable. –  Robert Harvey Mar 17 at 19:27
2  
2  
One possible implementation of an OOP system without any mutation: okmij.org/ftp/Scheme/#pure-oo –  Leushenko Mar 18 at 1:04

7 Answers 7

up vote 25 down vote accepted

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.

share|improve this answer
2  
Thank you very much, especially for the definition of the two core features. –  Hyperboreus Mar 17 at 19:58
    
Dynamic Dispatch is not a core feature of OOP. Neither really is Encapsulation (as you already admitted). –  OrangeDog Mar 18 at 13:25
1  
@OrangeDog Yes, there is no universally accepted definition of OOP, but I needed a definition to work with. So I picked something that is as close to the truth as I could get without writing a whole dissertation about it. However, I do regard dynamic dispatch as the single major distinguishing feature of OOP from other paradigms. Something that looks like OOP but actually has all calls resolved statically is really just modular programming with ad-hoc polymorphism. Objects are a pair of methods and data, and are as such equivalent to closures. –  amon Mar 18 at 13:36
    
"Objects are a pairing of methods and data" would do. All you need is something that has nothing to do with immutability. –  OrangeDog Mar 18 at 13:55

Immutability can be simulated in an OOP language, by only exposing object access points as methods or read-only properties that do not mutate the data. Immutability works the same in OOP languages as it does in any functional language, except that you may be missing some functional language features.

Your presumption seems to be that mutability is a core feature of object-orientation. But mutability is simply a property of objects or values. Object-orientation encompasses a number of intrinsic concepts (encapsulation, polymorphism, inheritance, etc.) that have little or nothing to do with mutation, and you would still derive the benefits of those features, even if you made everything immutable.

Not all functional languages require immutability, either. Clojure has a specific annotation that allows types to be mutable, and most of the "practical" functional languages have a way to specify mutable types.

A better question to ask might be "Does complete immutability make sense in imperative programming?" I'd say the obvious answer to that question is no. To achieve complete immutability in imperative programming, you would have to forego things like for loops (since you would have to mutate a loop variable) in favor of recursion, and now you're essentially programming in a functional manner anyway.

share|improve this answer
    
Thank you. Could you please elaborate a bit your last paragraph ("obvious" might be a bit subjective). –  Hyperboreus Mar 17 at 19:37
    
Already did.... –  Robert Harvey Mar 17 at 19:37
    
Thank you again and good answer. I have to digest it a bit. I also think that polymorphism and (not inheritance, but) derivation also figure quite centrally in functional languages. –  Hyperboreus Mar 17 at 19:40
1  
@Hyperboreus There are many ways to achieve polymorphism. Subtyping with dynamic dispatch, static ad-hoc polymorphism (aka. function overloading) and parametric polymorphism (aka generics) are the most common ways to do that, and all ways have their strengths and weaknesses. Modern OOP languages combine all these three ways, whereas Haskell primarily relies on parametric polymorphism and ad-hoc polymorphism. –  amon Mar 17 at 20:11
1  
@RobertHarvey You say that you need mutability because you need to loop (otherwise you have to use recursion). Before I started using Haskell two years ago, I thought I needed mutable variables, too. I'm just saying there's other ways to "loop" (map, fold, filter, etc.). Once you take looping off the table, why else would you need mutable variables? –  cimmanon Mar 18 at 16:16

Note, there's a culture among object oriented programmers where people assume if you're doing OOP that most of your objects will be mutable, but that's a separate issue from whether OOP requires mutability. Also, that culture seems to be slowly changing toward more immutability, due to people's exposure to functional programming.

Scala is a really good illustration that mutability isn't required for object-orientation. While Scala supports mutability, its use is discouraged. Idiomatic Scala is very much object oriented and also almost entirely immutable. It mostly allows mutability for compatibility with Java, and because in certain circumstances immutable objects are inefficient or convoluted to work with.

Compare a Scala list and a Java list, for example. Scala's immutable list contains all the same object methods as Java's mutable list. More, in fact, because Java uses static functions for operations like sort, and Scala adds functional-style methods like map. All the hallmarks of OOP—encapsulation, inheritance, and polymorphism—are available in a form familiar to object-oriented programmers and used appropriately.

The only difference you'll see is when you change the list you get a new object as a result. That often requires you to use different design patterns than you would with mutable objects, but it doesn't require you to abandon OOP altogether.

share|improve this answer

It's often useful to categorize objects as encapsulating values or entities, with the distinction being that if something is a value, code which holds a reference to it should never see its state change in any fashion which the code itself did not initiate. By contrast, code which holds a reference to an entity may expect it to change in ways beyond the reference-holder's control.

While it's possible to use encapsulate value using objects of mutable or immutable types, an object can only behave as a value if at least one of the following conditions applies:

  1. No reference to the object will ever be exposed to anything that might change the state encapsulated therein.

  2. The holder of at least one of the references to the object knows all the uses to which any extant reference might get put.

Since all instances of immutable types automatically satisfy the first requirement, using them as values is easy. Ensuring that either requirement is met when using mutable types is, by contrast, much more difficult. Whereas references to immutable types can be freely passed around as a means of encapsulating the state encapsulated therein, passing around state stored in mutable types requires either constructing immutable wrapper objects, or else copying the state encapsulated by privately-held objects into other objects which are either supplied by or constructed for the recipient of the data.

Immutable types work very well for passing values, and are often at least somewhat usable for manipulating them. They are not so good, however, at handling entities. The closest thing one can have to an entity in a system with purely-immutable types is a function which, given the state of the system, will report that attributes of some part thereof, or produce a new system-state instance which is like a supplied one except for some particular part thereof which will be different in some selectable fashion. Further, if the purpose of an entity is to interface some code to something that exists in the real world, it may be impossible for the entity to avoid exposing mutable state.

For example, if one receives some data over a TCP connection, one could produce a new "state of the world" object which includes that data in its buffer without affecting any references to the old "state of the world", but old copies of the world state which doesn't include the last batch of data will be defective and shouldn't be used since they will no longer match the state of the real-world TCP socket.

share|improve this answer
    
Great answer. Thank you. –  Hyperboreus Mar 18 at 22:57

In c# some types are immutable like string.

This seems to furthermore suggest that the choice has been strongly considered.

For sure it's really performance demanding to use immutable types if you have to modify that type hundred of thousand of times. That's the reason why it's suggested to use the StringBuilder class instead of the string class in this cases.

I've made an experiment with a profiler and using the immutable type is really more CPU and RAM demanding.

It's also intuitive if you consider that for modifying just one letter in a string of 4000 characters you have to copy every char in another area of the RAM.

share|improve this answer
6  
Frequently modifying immutable data does not need to be catastrophically slow as with repeated string concatenation. For virtually all kinds of data/use cases, an efficient persistent structure can be (often already has been) invented. Most of those have roughly equal performance, even if the constant factors are sometimes worse. –  delnan Mar 17 at 19:40
    
@delnan I also think that the last paragraph of the answer is more about an implementational detail than about (im)mutability. –  Hyperboreus Mar 17 at 19:41
    
@Hyperboreus: do you think I should delete that part? But how can a string change if it is immutable? I mean.. in my opinion, but for sure I can be wrong, that could be the main reason why object are not immutable. –  Revious Mar 17 at 19:42
1  
@Revious By no means. Leave it, so it causes discussion and more interesting opinions and points of view. –  Hyperboreus Mar 17 at 19:44
1  
@Revious Yes, reading would be slower, though not as slow as changing a string (the traditional representation). A "string" (in the representation I'm talking about) after 1000 modifies would be just like a freshly created string (modulo contents); no useful or widely used persistent data structure degrades in quality after X operations. Memory fragmentation is not a serious problem (you'd have many allocations, yes, but fragmentation is well a non-issue in modern garbage collectors) –  delnan Mar 17 at 21:19

Complete immutability of everything doesn't make much sense in OOP, or most other paradigms for that matter, for one very big reason:

Every useful program has side effects.

A program that does not cause anything to change, is worthless. You may as well not have even run it, as the effect will be identical.

Even if you think you're not changing anything, and are simply summing up a list of numbers you somehow received, consider that you need to do something with the result -- whether you print it to standard output, write it to a file, or wherever. And that involves mutating a buffer and changing the state of the system.

It can make a lot of sense to restrict mutability to the parts that need to be able to change. But if absolutely nothing needs to change, then you're not doing anything worth doing.

share|improve this answer
2  
I fail to see how your answer relates to the question as I didn't address pure functional languages. Take erlang for example: Immutable data, no destructive assignment, no hazzle about side effects. Also you have state in a functional language, only that the state "flows" through the functions, unlike the functions operating on the state. The state changes, but it doesn't mutate in place, but a future state replaces the current state. Immutability is not about whether a memory buffer is changed or not, it is about whether these mutations are visible from the outside. –  Hyperboreus Mar 17 at 23:32
    
And a future state replaces the current one how, exactly? In an OO program, that state is a property of an object somewhere. Replacing the state requires changing an object (or replacing it with another, which requires a change to the objects that refer to it (or replacing it with another, which...eh. You get the point)). You might come up with some type of monadic hack, where every action ends up creating a whole new application...but even then, the current state of the program has to be recorded somewhere. –  cHao Mar 17 at 23:58
5  
-1. This is incorrect. You're confusing side effects with mutation, and while they're often treated the same by functional languages, they are different. Every useful program has side effects; not every useful program has mutation. –  Michael Shaw Mar 18 at 1:47
    
@Michael: When it comes to OOP, mutation and side effects are so intertwined that they can not be realistically separated. If you have no mutation, then you can not have side effects without massive amounts of hackery. –  cHao Mar 18 at 2:00
    
And yet, in the comments on the question we find ... –  dmckee Mar 18 at 3:23

I think it depends on whether your definition of OOP is that it uses a message-passing style.

Pure functions don't have to mutate anything because they return values which you can store in new variables.

var brandNewVariable = pureFunction(foo);

With message passing style, you tell an object to store new data instead of asking it what new data you should store in a new variable.

sameOldObject.changeMe(foo);

It's possible to have objects and not mutate them, by making its methods pure functions that happen to live on the inside of the object instead of outside.

var brandNewVariable = nonMutatingObject.askMe(foo);

But it's not possible to mix message passing style and immutable objects.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.