←back to thread

498 points azhenley | 3 comments | | HN request time: 0.729s | source
Show context
EastLondonCoder ◴[] No.45770007[source]
After a 2 year Clojure stint I find it very hard to explain the clarity that comes with immutability for programmers used to trigger effects with a mutation.

I think it may be one of those things you have to see in order to understand.

replies(17): >>45770035 #>>45770426 #>>45770485 #>>45770884 #>>45770924 #>>45771438 #>>45771558 #>>45771722 #>>45772048 #>>45772446 #>>45773479 #>>45775905 #>>45777189 #>>45779458 #>>45780612 #>>45780778 #>>45781186 #
emil0r ◴[] No.45770884[source]
The way I like to think about is that with immutable data as default and pure functions, you get to treat the pure functions as black boxes. You don't need to know what's going on inside, and the function doesn't need to know what's going on in the outside world. The data shape becomes the contract.

As such, localized context, everywhere, is perhaps the best way to explain it from the point of view of a mutable world. At no point do you ever need to know about the state of the entire program, you just need to know the data and the function. I don't need the entire program up and running in order to test or debug this function. I just need the data that was sent in, which CANNOT be changed by any other part of the program.

replies(1): >>45772025 #
DrScientist ◴[] No.45772025[source]
Sure modularity, encapsulation etc are great tools for making components understandable and maintainable.

However, don't you still need to understand the entire program as ultimately that's what you are trying to build.

And if the state of the entire programme doesn't change - then nothing has happened. ie there still has to be mutable state somewhere - so where is it moved to?

replies(9): >>45773150 #>>45773166 #>>45773254 #>>45773339 #>>45774040 #>>45774256 #>>45774298 #>>45775098 #>>45778109 #
1. jimbokun ◴[] No.45773254[source]
> However, don't you still need to understand the entire program as ultimately that's what you are trying to build.

Of course not, that's impossible. Modern programs are way to large to keep in your head and reason about.

So you need to be able to isolate certain parts of the program and just reason about those pieces while you debug or modify the code.

Once you identify the part of the program that needs to change, you don't have to worry about all the other parts of the program while you're making that change as long as you keep the contracts of all the functions in place.

replies(1): >>45774720 #
2. DrScientist ◴[] No.45774720[source]
> Once you identify the part of the program that needs to change,

And how do you do that without understanding how the program works at a high level?

I understand the value of clean interfaces and encapsulation - that's not unique to functional approaches - I'm just wondering in the world of pure immutability where the application state goes.

What happens if the change you need to make is at a level higher than a single function?

replies(1): >>45776162 #
3. jimbokun ◴[] No.45776162[source]
Yes, obviously a program with no mutability only heats up the CPU.

The point is to determine the points in your program where mutation happens, and the rest is immutable data and pure functions.

In the case of interacting services, for example, mutation should happen in some kind of persistent store like a database. Think of POST and PUT vs GET calls. Then a higher level service can orchestrate the component services.

Other times you can go a long way with piping the output of one function or process into another.

In a GUI application, the contents of text fields and other controls can go through a function and the output used to update another text field.

The point is to think carefully about where to place mutability into your architecture and not arbitrarily scatter it everywhere.