4

I feel this is a bad question because I probably do not understand what I am talking about. In my effort to learn about functional programming, I became stumped on understanding the idea of immutable stuff. I have been using C# as a hobby for years and I think I do not even understand OOP principles very well. I use a class as a bucket of public and private data with methods pinned to it. It's partially mutable and partially immutable I guess? So I sort of want to step away from comparing and contrasting OOP and pure FP for a second and just think about "mutable" (can change) and "immutable" (cannot change) stuff.

People say it is good to make things immutable and I believe them. But how can a program do anything if you cannot change data? Whether you're talking FP or OOP, it seems that you need at least one giant mutable data structure (like a database) since all your functions or objects are immutable. But that sounds very impractical. I can think of it this way: x = f1(f2(f3(f4(f5( y ))))) where y is the user input and x is the output. The program is the immutable functions 1 through 5. But again, this appears very impractical. I think I understand the benefits of immutable things but I just don't understand how to use them properly for a large program.

Again, consider me a baby in the programming world. I would appreciate book or book chapter recommendations. And feel free to tell me if I'm asking the wrong question.

  • 1
    The functional approach is a very useful one in many respects, but for a while fanatics were hyping "purity" and immutability so badly that it almost seemed like the assignment operator was now considered harmful. The truth as you say is that a program that modifies nothing is utterly useless for virtually all industrial applications, so well done for identifying that immutability is not a silver bullet. – Steve Sep 30 at 17:49
  • 1
    While not entirely immutable, consider Git as an example - committing changes into a Git repository does not overwrite any earlier changes or commits, it records a set of changes in a new hash in the repository timeline. Git history is intended to be treated as immutable. Blockchain also works in a similar fashion. – Ben Cottrell Sep 30 at 17:52
  • 2
    It may help to look at your own code that deals with strings in C# - they are immutable but pretty much no one have trouble producing non-trivial results with them... – Alexei Levenkov Sep 30 at 18:30
  • 2
    Immutable just means things don't change once created. However, we can always create new things, and though they are also immutable, creating new things represents new state!! – Erik Eidt Oct 1 at 2:49
8

Mutable:

public void DoubleArray(int[] array)
{
    for (int i=0; i<array.length; i++)
        array[i] *= 2;
}

Immutable:

public int[] DoubleArray(int[] array)
{
    int[] result = new int[array.length];

    for (int i=0; i<result.length; i++)
        result[i] = array[i] * 2; 

    return result;
}

See the difference? The immutable code is perfectly feasible. In fact, this is how strings are treated in many languages, including Java and C#.

Some nice things about immutability:

  1. Your code is easier to reason about, particularly in a multi-threaded context, because you don't have to worry about anything being modified.

  2. You get a running history of "changes."

  3. You can "memoize," which can actually improve performance.

| improve this answer | |
  • I think you left out the indexer on the mutable example, and the "immutable" example would probably be better considered a "non-mutating" example using mutable types, as there is no enforcement of immutability (which is exploited to build the array piecewise). – Steve Sep 30 at 18:29
  • It's not intended to be an example of a language feature, only to demonstrate the concept of immutability. The "immutable" method does not modify the original array. See Euphoric's explanation below. – Robert Harvey Sep 30 at 18:33
  • 1
    The other answers below very helpful as well. I selected this one as the answer just because I liked the code example. Thanks a lot. I guess I actually use immutable functions a lot. It's all about making the change in the form of creating a new bit of data from the old it seems. – Julian Oct 1 at 22:09
7

Here's what most people seem to miss about immutability. Consider the following function:

def factorial(n: Int): Int = if (n == 0) 1 else n * factorial(n - 1)

This function is completely immutable. So does n ever change? Yes and no. One instance of n doesn't change, but you quite frequently get a completely new n and the reference to the old n is lost. n can even simultaneously refer to different values in different threads or different levels of the stack within the same thread.

This is how immutable programs 'change' things. Multiply this effect by every function in the program and there is quite a bit of apparent change going on, but within any given function everything is constant. It's almost paradoxical.

| improve this answer | |
  • This makes a lot of sense. Thank you. It turns out, I make a lot of functions like that but now I understand what people mean when they say immutable. – Julian Oct 1 at 22:11
4

You are correct that perfectly immutable program, one that relies only on it's input when started wouldn't be much useful.

But the idea of immutability is not to make program completely immutable, it is to abstract the mutable state away and push the mutable state to the edges of the program. This way, the actual core of the program, the one written by a programmer of an application can be immutable. There will still be mutability, but it will be hidden in libraries. Which means that programmer won't come into contact with (arguably dangerous) mutable state.

I'm not an expert on functional programming and immutable state, but two ideas come to mind.

IO monad is how input/output of functinal/immutable program can read and write into it's mutable state. Imagine a function readCharacter():Func<IO,Char>, this function when called, returns another function, which reads IO and returns character. The whole point of this is that many such function, which work on IO, can be compose together which would result into something like Program(IO). This program then takes IO into its outpu and it's inside can be perfectly immutable, pure and won't know it is actually doing side effects.

Second idea is that of reactive programming. In this paradigm, the central concept is that of stream of events. Those events can be inputs like keypresses, mouse clicks or files received over the network, or outputs, like changing text on a screen or sending a file. Then, methods can be applied to those streams to filter them, transform them, join them and do all kind of shenanigans with them. Then, your program could very well be one that has one input of stream of events and one output of stream of events and everything in the middle is immutable and pure. The mutability is hidden in the implementation of the streams and methods operating on those streams. This is how functional/immutable UIs can be made.

| improve this answer | |
  • 3
    For state, you wouldn't use the IO monad, but a more restricted one. IO means "any side-effect at all" which also means "absolutely no guarantees". For state, the State monad would be more appropriate, or even more restricted, the Reader or Writer monad. One interesting thing about the State monad is that you can have a SoftwareTransactionalMemory monad or a DistributedDatabase with the same interface, so you can parallelize and / or distribute your code without changing how it interacts with state – Jörg W Mittag Sep 30 at 18:43
  • For example, the State monad can still guarantee that you won't format the hard disk or launch the missiles, but the IO monad can't. – Jörg W Mittag Sep 30 at 18:44
  • @JörgWMittag Thanks for clarification. I don't think that level of detail is necessary for my answer. – Euphoric Sep 30 at 18:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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