Hacker News new | ask | show | jobs
by unoti 856 days ago
> Immutable data is not a “foundation of scalability and robustness”.

It may not be the only way to get to scalability and robustness. But it certainly is the cornerstone of how Erlang gets there.

1. First, the way Erlang treats data ensures that every piece of data can be sent over the wire by default. This helps pave the way for another amazing characteristic of Erlang, and that is when you refer to and use an object, it's essentially transparent to your code whether that object is on this machine or another machine in the cluster. This would not be possible without the fact that all data structures are remotable, which is enabled by the immutable data. (See also side note below.)

2. The immutable data also leads to clean rollback semantics, making it easy to always have a self-consistent state of the system ready to use even after some kind of fault.

3. The immutable data also leads to very clean and easy ways to handle multithreading because you never have to worry about making object copies. You can be assured that it's ok for two threads to use the same memory object because there's no way either of them can change it.

Side note: Alan Kay, the inventory of OO, has said that people get the entire idea of what he was talking about all wrong. He said that object orientation isn't about objects, but its about communication. He was talking about the idea of an object being more like what we'd call a web endpoint today, where when you instantiate it you communicate with it by sending it messages. It's funny to me that a functional language like Erlang best embodies that OO idea today. Go code can, too.

"I'm sorry that I long ago coined the term 'objects' for this topic because it gets many people to focus on the lesser idea. The big idea is 'messaging'" - Alan Kay <https://en.wikipedia.org/wiki/Alan_Kay>

He goes on in the original underlying document to say "OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things." All of these ideas are front-and-center in Erlang (and by extension Elixir).

2 comments

As an aside: The particular technique used in the OP (resource objects) is actually not transparent. If you send the object handle to another machine, it will have an opaque handle that it can't do anything with apart from storing and sending around. However, if the other machine sends it back (and the resource object hasn't been deallocated in between) it will be the same as the one that you sent.
> you instantiate it you communicate with it by sending it messages

Does this mean a web-endpoint has to be immutable? If you send it the same parameters multiple times, is it required to respond with the same response every time? If not, does that not mean it is in fact mutable?

I read elsewhere that in Elixir programs, there is no difference in messaging a local "agent" or a remote one? The caller does not know whether the other party is remote or not. Is it still guaranteed to be immutable?

Just asking since I don't know much about Elixir.

> Does this mean a web-endpoint has to be immutable? If you send it the same parameters multiple times, is it required to respond with the same response every time? If not, does that not mean it is in fact mutable?

This is a concept called purity, and it's only loosely related to immutability. Immutability makes purity easier to implement and reason about, but does not guarantee it. Erlang/Elixer are not pure. For example, `DateTime.now("Etc/UTC")` will return different things at different times.

As a counter-example, Haskell functions are pure, so the `getCurrentTime` function cannot return a value directly as it would be different every time. Instead it uses the return type `IO UTCTime` which act like instructions on how to calculate the time, rather than the time itself.

https://en.wikipedia.org/wiki/Pure_function

When they say all the data in Erlang/Elixir is immutable, it does not mean that there is no state. There's definitely data in the programs that change values, because like you point out, how in the heck can you write a useful system that doesn't have any state anywhere?

State or data that changes values is typically put in one of 3 different places:

1. On the stack. It's pretty typical to have a function like handle_message(app_state, request). The current state of the app is in the call parameters. At the end of this message, handle_call() would call itself again with the new updated state. Somewhere else in the system we keep track of the last value of that state, and if handle_call crashes, we just use the last state.

2. Another place to hold state is in external storage somewhere.

3. The third main place to hold state is via references to other objects, which do #1 or #2 above.

Regarding whether there is a difference between messaging local versus remote objects-- there's an operator for sending messages to another object. It works the same for local and remote. I think it's possible to inspect the actor address and see where it is, but the mechanism works the same.