4 ms·
I think that a big part of the problem is pervasive access to global state. Given a block of code, it's impossible to tell what effect it (or its sub-calls) mig
by jamii 13y ago
I think that a big part of the problem is pervasive access to global state. Given a block of code, it's impossible to tell what effect it (or its sub-calls) might have on the global state.
A common design pattern in clojure is to have a single massive data-structure that represents all application state, but to take it apart recursively whilst updating so that each function is only passed the pieces of state that are relevant. That way you can look at a function and immediately know what it can and can't read/write out of the global state.
A nice way of doing this in an imperative language might be to pass bits of the global data structure by reference (ala lenses) so that a given function can only read/write state contained in its arguments. The data is still global in the sense that it is all accessible from the root object and is not encapsulated, but access can be restricted on a per-function basis.
- Udo 13y ago> Given a block of code, it's impossible to tell what effect it (or its sub-calls) might have on the global state. That's true. The equivalent effect in the "all local" paradigm is local objects the state of which can't meaningfully be understood or manipulated by neither the programmer nor other objects, leading again to unexpected behavior that is painful to track down. A lot of the precautions that are common sense when working with global data are already instinctively followed (or at least understood) by most programmers I think. In effect the lenses are already working when there's an understanding when and where manipulation occurs. This mostly coincides with the notion that complex data should be manipulated by a well-defined model and wherever sensible there should be only one mechanism for doing it.
- mercurial 13y ago> That's true. The equivalent effect in the "all local" paradigm is local objects the state of which can't meaningfully be understood or manipulated by neither the programmer nor other objects, leading again to unexpected behavior that is painful to track down. def foo(x): x_plus_one = add_one(x) x_plus_one_times_two = times_two(x_plus_one) return x_plus_one_times_two Here is a function with some local state. Which part do you feel "can't meaningfully be understood or manipulated by [...] the programmer"? I'm not trying to bait you, but I'm struggling to grasp the argument you are making.
- Udo 13y agoOf course it's always possible to construct an infinite number of neat little functions that are not like that. However, I remember lots of times when I had to fight with some external libraries that had exactly the problem I'm describing. I don't quite understand how your illustration is relevant. The issue is not that simple and well-defined functions can't have any internal state that is easy to follow. I didn't argue this doesn't exist. I said that many times it's not what you find out there. Abstractly speaking, when I say "A often has the property B", you can't meaningfully counter that with "you're wrong, here's an example where !B".
- mercurial 13y agoI think I have misread your comment. I thought you were making sweeping statements about local state in general. That said, I'd still appreciate an example. I haven't noticed any special issues wrt to understanding programs made of immutable-from-the outside objects or local variables.
- usea 13y agoHi. I'm sorry to be pedantic, but the confusion here stems from your use of "equivalent" in responding to a quote that used "impossible." You never said "often," but you did imply you were describing an also-impossible thing. Fortunately the confusion is cleared up now.
- lomnakkus 13y agoImmutable local state is (as you've observed in that example) harmless, but once you start mutating closed-over state, you've given up completely on referential transparency[1] which gives you a lot of power when reasoning about what code does (and doesn't!) do. [1] https://en.wikipedia.org/wiki/Referential_transparency_%28computer_science%29 https://en.wikipedia.org/wiki/Referential_transparency_%28co...
- davexunit 13y agoI think closed-over mutable state certainly has its place. For example, delay and force in Scheme. Mutable local state is used to memoize the result of the delayed procedure. Of course, it would be terrible for a large program to keep all of its state within a closure. You eliminate the benefits of live-coding from your REPL at that point since you can only directly affect the top-level environment.