3 ms·
> I would argue that, from the perspective of our program, it is not more or less mutable than any other thing. The reason for this, is that in Elixir, all muta
by mrkeen 2y ago
> I would argue that, from the perspective of our program, it is not more or less mutable than any other thing. The reason for this, is that in Elixir, all mutating state requires calling a function to observe it.
Are you never not inside a called function?
This just sounds like pervasive mutability with more steps.
- colonwqbang 2y agoIt sounds like all old bindings to the value stay the same. So you have a "cell" inside which a reference is stored. You can replace the reference but not mutate the values being referred to. If so, this sounds a lot like IORef in Haskell.
- finder83 2y agoThe functions don't return a mutable version of a variable or anything. You still get an immutable copy (it may not be an actual copy, I don't know the internals) of the state, and the state he's referencing in a Genserver is the current state of a running process that runs in a loop handling messages. For example in liveview, each connection (to an end-user) is a process that keeps state as part of the socket. And the editing is handled through events and lifecycle functions, not through directly mutating the state, so things tend to be more predictable in my experience. It's kind of like mutation by contract. In reality, it's more like for each mailbox message, you have another loop iteration, and that loop iteration can return the same value or a new value. The new values are always immutable. So it's like going from generations of variables, abandoning the old references, and using the new one for each iteration of the loop. In practice though, it's just message handling and internal state, which is what he means by "from the perspective of our program". You typically wouldn't just write a Genserver to hold state just to make it mutable (though I've seen them used that way), unless it's shared state across multiple processes. They're not used as pervasively as say classes in OOP. Genservers usually have a purpose, like tracking users in a waiting room, chat messages, etc. Each message handler is also serial in that you handle one mailbox message at a time (which can spawn a new process, but then that new process state is also immutable), so the internal state of a Genserver is largely predictable and trackable. So the only way to mutate state is to send a message, and the only way to get the new state is to ask for it. There's a lot of benefits of that model, like knowing that two pieces of code will never hit a race condition to edit the same area of memory at the same time because memory is never shared. Along with the preemptive scheduler, micro-threads, and process supervisors, it makes for a really nice scalable (if well-designed) asynchronous solution. I'm not sure I 100% agree that watching mutating state requires a function to observe it. After all, a genserver can send a message to other processes to let them know that the state's changed along with the new state. Like in a pub-sub system. But maybe he's presenting an over-simplification trying to explain the means of mutability in Elixir.
- borromakot 2y ago`send` is a function. `receive` is a special form but in this context it counts as a function
- bux93 2y agoI think the author means "I said everything is immutable, and rebinding is obviously changing something, but the thing it changes doesn't count!". The idea being, if you read a bunch of code, none of the variables in that piece of code can have the value of it changed unless there is some explicit line of code.
- borromakot 2y agoI didn't mean you "must be inside of a function". If you call `Process.put(:something, 10)`, any references you have to whatever was already in the process dictionary will not have changed, and the only way to "observe" that there was some mutating state is that now subsequent calls to `Process.get(:something)` return a different value than it would have before. So with immutable variables, there is a strict contract for observing mutation.