TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Immutability is not enough

271 pointsby r4umabout 9 years ago

29 comments

joramsabout 9 years ago
&gt; This is exactly the kind of problem that functional programming was supposed to help us avoid!<p>No, no it isn&#x27;t. Just like you wouldn&#x27;t expect 2 * 3 + 8 to suddenly return 22 when you intend it to, you shouldn&#x27;t expect the order in which you apply functions to not matter.<p>When you pass around a changing state object to every step of your program, you are effectively doing normal imperative programming with global-ish state.
评论 #11396753 未加载
评论 #11396173 未加载
jasonkesterabout 9 years ago
Oh dear.<p>I read the first half of this article watching him take the simple OO game loop and iteratively make it worse and worse, leaving it nearly unreadable and impossible to follow the logic or know what the state would be at any given moment. Then I came to this line:<p><i>Let’s take a moment to appreciate a few of the things we’ve gained by rewriting this code in a functional style</i><p>He actually thinks that he has improved the program. By piling functions up six deep and replacing pos.x += 3 with four lines of object accessor code (using strings for property names). Oh dear.<p>The second half of the article, where he realizes that he has not actually gained anything by ruining his game is just the icing on the cake.<p>I don&#x27;t feel as though I&#x27;ve been sold on the benefits of Immutability today.
评论 #11396699 未加载
评论 #11396948 未加载
评论 #11396550 未加载
评论 #11396484 未加载
评论 #11396553 未加载
victorNicolletabout 9 years ago
The bugs described in the article stem from the existence of a &quot;state&quot; type. If you&#x27;re allowed to call draw() on the result of handleCollisions(), but not on the result of processInput(), that means there are actually two state types in your program:<p><pre><code> draw : cleanState -&gt; unit handleCollisions : dirtyState -&gt; cleanState processInput : cleanState -&gt; dirtyState </code></pre> These signatures allow draw(handleCollisions(processInput(state)) but forbid the incorrect ordering draw(processInput(handleCollisions(state)).<p>Effect systems boil down to &quot;discovering&quot; these types eventually, but it is easier for a human to think in terms of what invariants are enforced by a given type. Even if there is no language support for actually checking those invariants before execution.
评论 #11395518 未加载
评论 #11395565 未加载
zbyabout 9 years ago
Can anyone explain why it is:<p><pre><code> var newState = drawManuel( drawBackground( processInput(state))); </code></pre> and not:<p><pre><code> var newState = processInput(state); drawManuel(newState); drawBackground(newState); </code></pre> When I read the first my intuition is that application of drawManual and drawBackground is important for the value of newState. The second one makes it clear that newState does not depend on drawManual (or drawBackground).<p>It would also make the first bug more easier to spot:<p><pre><code> var newState = handleCollisions(state) newState = processInput(newState) drawBackground(newState) drawManuel(newState) </code></pre> The problem with the order of handleCollisions and processInput is now more visible because now it is obvious that just those two change the state - so we concentrate on them. And there are less parentheses.<p>(Initially I used another variable here to make it more functional - but then I decided this is useless - we are still in an imperative language)<p>I have a feeling that the author have some strange idea about what functional means. I stopped reading after this part.
评论 #11396222 未加载
_0w8tabout 9 years ago
It is interesting that the solution for order dependency problem essentially turns functions that update the state into functions that writes a program in a mini-language. When interpreted, the language updates the state. In Haskell this is known as Operational Monad [1].<p>The nice thing with that approach is that it decouples complex application-specific logic from state management allowing to test both components separately. Another bonus is that it enables things like Elm&#x27;s time traveling debugger [2].<p>The drawback is that this adds maintenance burden as now one has to deal with the intermediate language. If that language is a poor fit for the problem, the burden can be rather high. This is especially bad in JavaScript where lack of rich static types makes generating programs and writing an interpreter is rather error prone.<p>[1] <a href="https:&#x2F;&#x2F;wiki.haskell.org&#x2F;Operational" rel="nofollow">https:&#x2F;&#x2F;wiki.haskell.org&#x2F;Operational</a><p>[2] <a href="http:&#x2F;&#x2F;debug.elm-lang.org&#x2F;" rel="nofollow">http:&#x2F;&#x2F;debug.elm-lang.org&#x2F;</a>
Kiroabout 9 years ago
&gt; However, we still don’t know what they do with the state. Do they modify it, or do they only read it?<p><pre><code> var newState = drawManuel( drawBackground( processInput(state))); </code></pre> I don&#x27;t see how this makes it more readable. I still don&#x27;t know which functions actually modify the state. This is what I imagined the result to be:<p><pre><code> var newState = processInput(state); drawBackground(newState); drawManuel(newState);</code></pre>
cousin_itabout 9 years ago
Don&#x27;t try to use functional programming for GUIs, simulations, or games. That&#x27;s what OO was invented for.<p>Don&#x27;t try to use OO for compilers or formal verification. That&#x27;s what FP was invented for.<p>Don&#x27;t try to use OO or FP for operating systems. That&#x27;s what imperative languages were invented for.<p>Anyone who insists on a single style for the whole software industry is probably underinformed and overconfident.
评论 #11397169 未加载
评论 #11397319 未加载
评论 #11397361 未加载
评论 #11397201 未加载
raspasovabout 9 years ago
Here&#x27;s a ClojureScript + core.async + Om + my own animation lib solution. No surprises, no weird bugs. Dead simple functional code + CSP = WIN! : )<p><a href="https:&#x2F;&#x2F;gist.github.com&#x2F;raspasov&#x2F;e894a0c6c26e5814d752b3fc9075c601" rel="nofollow">https:&#x2F;&#x2F;gist.github.com&#x2F;raspasov&#x2F;e894a0c6c26e5814d752b3fc907...</a><p>Here&#x27;s also the anim lib gist, if anyone is interested <a href="https:&#x2F;&#x2F;gist.github.com&#x2F;raspasov&#x2F;f9ca712571efd932169e" rel="nofollow">https:&#x2F;&#x2F;gist.github.com&#x2F;raspasov&#x2F;f9ca712571efd932169e</a>
评论 #11396535 未加载
ktRolsterabout 9 years ago
&quot;You will never find a programming language that frees you from the burden of thinking about bugs&quot; <a href="https:&#x2F;&#x2F;xkcd.com&#x2F;568&#x2F;" rel="nofollow">https:&#x2F;&#x2F;xkcd.com&#x2F;568&#x2F;</a>
评论 #11396394 未加载
theseoafsabout 9 years ago
It seems what the author learned is that &quot;programming languages sometimes let you do things in the wrong order&quot;, which is so obvious that it&#x27;s kind of a non-observation.<p>Anyway, functional programming on its own doesn&#x27;t get you there, but functional programming with a solid type system does prevent this bug from happening.
akkartikabout 9 years ago
Great article, feeds all my prejudices. For example, I&#x27;m tempted to link to it in <a href="http:&#x2F;&#x2F;akkartik.name&#x2F;post&#x2F;modularity" rel="nofollow">http:&#x2F;&#x2F;akkartik.name&#x2F;post&#x2F;modularity</a> at the point where I say that &quot;There seems the very definite possibility that the sorts of programs we humans need to help with our lives on this planet intrinsically <i>require</i> state.&quot;
评论 #11396073 未加载
评论 #11395507 未加载
jw-about 9 years ago
The problem doesn&#x27;t really have anything to do with immutability; the problem is dependency and composition. E.g.<p>f :: A -&gt; B<p>g :: B -&gt; C<p>will let me write g(f(x)), but not f(g(x)). It does not matter if f and g are &#x27;pure&#x27;, the point is that f must come before g. I think the mistake is to think that functional programming is about immutability, and that immutability solves the problems. Immutability is there to keep the types honest, it is fine to have effects aslong as we are upfront about them, and don&#x27;t conceal them under false names such as &quot;int&quot; and &quot;bool&quot;.
fnordsenseiabout 9 years ago
Just as it&#x27;s possible to model immutability on top of mutable structures, it&#x27;s possible to model mutability on top of immutable structures. Regardless of which way you go, you end up with the properties associated with the kind of structure you&#x27;re building. This is not too surprising, I would think.
DanielBMarkhamabout 9 years ago
There&#x27;s a funky thing going on here because of the environment this guy is using: Javascript and a JS library to handle immutability.<p>Because of the way he&#x27;s coding, he&#x27;s doing a lot of horsing around with several things at once. He&#x27;s not writing functions and then composing them. He&#x27;s refactoring multiple functions at the same time. As it turns out, this difference is important. Looking at it from one angle, from small pieces into larger pieces, you&#x27;ll be solving the order of functions almost immediately. Looking at it from another angle, from big pieces into smaller pieces, you solve problems in a different order. You make pieces with names on them that do what you want, then you look at whether there&#x27;s support in the code to do what you want to do, regardless of how that integrates. In fact, you end up (as he does) integrating later. You&#x27;re not <i>composing</i>, you&#x27;re <i>decomposing</i>.<p>This is why one of the recommended ways to do FP is to use the REPL and get the core, toughest function working first. Then start composing. Work outwards from there.<p>The first function you&#x27;d probably write in this case would perhaps be moveTheGuy which would move the guy from one place to another. You would immediately be solving the problem of whether or not the guy could actually move. Contrast this with the first function being updateTheWorld, where you can start inventing all kinds of stuff that might or might not happen. Then you horse around trying to figure out what should go under updateTheWorld<p>I remember the first conference talk I saw with a guy talking about F#. It was still new in the industry, and many of the folks who were using it were true-blue OO coders.<p>The guy gets up, shows some code, then goes behind-the-scenes to show us the &quot;real&quot; C# code. &quot;As you can see, all this really is? It&#x27;s do-while loop. You could code this way with C# and never touch F#&quot;<p>Yeah sure, but the environment you&#x27;re in can help lead you to write better or worse code. It seems to me if I wanted to do pure functional stuff and Javascript I&#x27;d be pretty freaking careful how I coded. Lots of things there that point you in the wrong direction. Functional code just isn&#x27;t regular code with all sorts of weird syntax; it&#x27;s actually a different way of looking at solving problems.
_pmf_about 9 years ago
It seems to be a common trend to claim that functional programming solves the problem of state.<p>It can solve the problem of accidental state in the solution space, but it obviously cannot change the fact that a specific problem space has stateful characteristics.<p>Don&#x27;t introduce accidental state, yes. But embrace the problem&#x27;s states as first class elements of your solution and don&#x27;t try to hide them.
评论 #11398121 未加载
RichieAHBabout 9 years ago
I don&#x27;t see how functional programming would ever solve the problem of chronology. If the collision engine needs to know the new position <i>in that frame</i> then it needs to run that code first. You can&#x27;t just run code whenever and expect functional programming to fix it. Nor will assigning different areas of the state to specific functions fix that either.<p>I think immutable data solves a lot of headaches and using Redux and Immutable together in our current stack has shown me some of the benefits of immutability and a more functional programming style. However, much of this article was about immutability not being a silver bullet for things that, IMO, were never going to be solved by immutability. It&#x27;s like saying it would be solved by writing everything in Haskell, there are some &quot;complexities&quot; that can&#x27;t be hidden, e.g. order of events. Maybe I missed something.
评论 #11395837 未加载
yasonabout 9 years ago
<p><pre><code> var newState = drawManuel( drawBackground( processInput(state))); </code></pre> This isn&#x27;t how functional programming must work to be functional programming. The point is always to write as much as possible in functional, preferably immutable style, if only it fits well. You can write a large portion of your program that way.<p>The next sacrifice is to glue the functional calls together with more of a stateful approach, but preferably keep the mutable state more contained. For example, having a single function that handles the state, calls into the immutable functional code to do the heavy lifting, then sew everything together and ideally return something that is immutable and stateless. Like little bubbles of state where absolutely needed. For example, draw() calls in the above example can&#x27;t be functional as drawing relies on side-effects. There&#x27;s nothing to return from a drawing function, so those can&#x27;t natively be chained into nested function calls.<p>The final level is usually some hodge-podge state management at the very top level where it becomes unavoidable in order to keep things organised and beautiful. There&#x27;s always some state, so you&#x27;ll have to do it somewhere, but the more localized and minimized the better state management it is.
susi22about 9 years ago
I&#x27;ve said this a few years back in some other thread but it&#x27;s so fitting here I&#x27;ll say it again:<p>In a few years down the road I hope that the JS folks take a very very close look at Rule engines. These kind of errors can be easily avoided with them.<p>There is actually folks in the Clojurescript world using clara-rules for Browser state&#x2F;rendering and it apparently works very well for them. I really wish some bigger player would push in that direction.
评论 #11398566 未加载
lliamanderabout 9 years ago
I really liked this post. It reminds me of a similar post by James Hague[0]<p>A number of people seem to be hung up on what is meant by FP advocates saying &quot;order doesn&#x27;t matter&quot;. In all the literature I have read when I first learned about FP it seemed pretty clear to me that it meant &quot;function composition is associative&quot;, <i>not</i> &quot;function composition is commutative&quot;.<p>But whether this is obvious is beside the point. The hypothetical confused programmer is merely a rhetorical device to set the reader up to think more deeply about how they handle state. FP teaches us to push state changes to the boundaries of the system. OK, once it is there, now what do we do with it?<p>We handle it declaratively[1]. That&#x27;s what treating the updates as data allows.<p>[0]<a href="http:&#x2F;&#x2F;prog21.dadgum.com&#x2F;189.html" rel="nofollow">http:&#x2F;&#x2F;prog21.dadgum.com&#x2F;189.html</a> [1]<a href="https:&#x2F;&#x2F;awelonblue.wordpress.com&#x2F;2012&#x2F;01&#x2F;12&#x2F;defining-declarative&#x2F;" rel="nofollow">https:&#x2F;&#x2F;awelonblue.wordpress.com&#x2F;2012&#x2F;01&#x2F;12&#x2F;defining-declara...</a>
hellofunkabout 9 years ago
Here is a related article for anyone curious about, or who uses, persistent&#x2F;immutable data structures:<p><a href="http:&#x2F;&#x2F;concurrencyfreaks.blogspot.nl&#x2F;2013&#x2F;10&#x2F;immutable-data-structures-are-not-as.html" rel="nofollow">http:&#x2F;&#x2F;concurrencyfreaks.blogspot.nl&#x2F;2013&#x2F;10&#x2F;immutable-data-...</a>
wodenokotoabout 9 years ago
I&#x27;ve never really dived into functional programming but often end up reading a lot about it here.<p>There&#x27;s always been something about state and immutability that irked me the wrong way and I&#x27;m very happy to see it being put into words and code examples.
评论 #11395589 未加载
sesquipedalianabout 9 years ago
First of all, it&#x27;s great that you&#x27;re exploring functional programming paradigms and their applicability to game programming&#x2F;state management.<p>That being said I have to point out some things that bothered me: I believe you&#x27;re conflating immutability and commutativity -- these things are not the same thing. Functional programming does not absolve you of paying attention to the order of operations. For example if you had two functions plus1 and plus2, you can order those any way you like since summation is commutative. However if you had plus1 divide2 functions, you have to pay attention to the order of application due to non-commutativity.
chriswarboabout 9 years ago
I think this is an example of something I see often, where a particular idea (e.g. immutability, interfaces, modularity, etc.) gets confused with a particular feature of a particular language which shares the same name. In this case, the author&#x27;s code isn&#x27;t using immutability; it just-so-happens to be creating an object called &quot;Immutable.Map&quot;.<p>Following the author&#x27;s terminology, mutability is when we replace the contents of a memory location with different values, e.g.:<p><pre><code> Time | RAM ------+-------------------------------- 0 | foo 1 | bar 2 | baz . . . </code></pre> The author is using the term immutable to mean never replacing the contents of a memory location, so in their view this is immutability:<p><pre><code> Time | RAM 1 | RAM 2 | RAM 3 | ------+-------+-------+-------+--... 0 | foo | | | 1 | foo | bar | | 2 | foo | bar | baz | . . . . . . . . . . . . </code></pre> However, this is really just an implementation detail; Javascript programming isn&#x27;t really about values in RAM (unlike, e.g. C where pointers are first-class values in the language). Instead, Javascript is conceptually built around variables, objects, scope, etc. So let&#x27;s see how these RAM details translate to the values of variables.<p>The &quot;mutable&quot; version:<p><pre><code> Time | &quot;state&quot; var ------+------------- 0 | foo 1 | bar 2 | baz . . . </code></pre> The &quot;immutable&quot; version:<p><pre><code> Time | &quot;state&quot; var 0 | &quot;state&quot; var 1 | &quot;state&quot; var 2 | ------+---------------+---------------+---------------+--... 0 | foo | | | 1 | foo | bar | | 2 | foo | bar | baz | . . . . . . . . . . . . </code></pre> So far so good. However, scope plays a large part in Javascript programming: we can only access variables which are in scope, and what&#x27;s more the <i>same</i> variable name can refer to <i>different</i> values depending on the scope we&#x27;re in. This is where the author confuses the <i>concept</i> of immutability with the name of a library they just-so-happen to be using. Their code keeps generating new scopes, in which the variable name &quot;state&quot; refers to a different value than in the previous scopes. Conceptually, the variable &quot;state&quot; is not immutable because it keeps referring to different things, even though the implementation details could be argued to be immutable.<p>As an analogy, consider a display which shows the current value of a stock price. That is certainly not immutable, and trying to use that reading to perform calculations will be tricky since it keeps changing. This is like the author&#x27;s original, mutable &quot;state&quot; variable.<p>Now consider a plotter drawing a graph of how that price varies over time:<p><pre><code> | | _--. ____ Price | &#x2F; \ &#x2F; \ |__&#x2F; \__; \__&#x2F; | +----------------------------------- Time ^ | Now </code></pre> This is like the author&#x27;s &quot;immutable&quot; version, where values are never changed once they&#x27;re defined. This seems more useful for performing calculations, however, because the author keeps creating new scopes, they have no access to these old values! We have no access to the graph paper, we&#x27;re only allowed to see the current position of the pen; which is exactly the same as if we only had the original display!<p>If we take scope into account, we actually get the following:<p>Mutable version:<p><pre><code> Time | Scope | Current &quot;state&quot; ------+-------+----------------- 0 | 0 | foo 1 | 0 | bar 2 | 0 | baz . . . . . . </code></pre> Immutable version:<p><pre><code> Time | Scope | Current &quot;state&quot; | &quot;state&quot; var 0 | &quot;state&quot; var 1 | &quot;state&quot; var 2 | ------+-------+-----------------+---------------+---------------+---------------+--... 0 | 0 | foo | foo | | | 1 | 1 | bar | foo | bar | | 2 | 2 | baz | foo | bar | baz | . . . . . . . . . . . . . . . . . . </code></pre> I do think the author has a few good points to make; however, I don&#x27;t think it&#x27;s an argument between being mutable vs. being immutable, so much as one between being implicit vs. being explicit.
评论 #11397199 未加载
评论 #11399447 未加载
tomeabout 9 years ago
The point of functional programming (or any good programming style, really) is to eliminate unneccesary dependencies (by which process the necessary dependencies are clarified) <i>not</i> to remove necessary dependencies (which by definition is impossible).
leshowabout 9 years ago
reminds me of Elm&#x27;s Effects system.<p>great article.
hathymabout 9 years ago
sounds like a solution looking for a problem.
dschiptsovabout 9 years ago
Immutability as absense of over-writes or mutations of existing values (in Erlang one just introduces a new binding for a new value) is obviously enough.<p>State and I&#x2F;O is easily incapsulable inside closures with CPS or with explicit message passing.<p>For a lazy language one needs some ADT, like Monad, for explicitly &quot;enforcing&quot; a strict order of evaluation for a specific set of expressions, because I&#x2F;O <i>implies</i> a strict order. Think of it as a transformation from a set to sequence (by <i>defining an order</i> as an ADT).<p>Lifting State or IO into Monadic world is mere a trick to satisfy a typechecker <i>and</i> enforce a strict order by using an ADT. A strict language with optional lazynes could use ordinary type-tags.<p>Nothing to see here.
评论 #11397396 未加载
kordlessabout 9 years ago
Not one mention of the blockchain in the story or here. How interesting.
riprowanabout 9 years ago
As a non-game-programmer, the idea of &quot;collision detection and prevention&quot; seems like a case of bad modeling.<p>In the real world, two objects don&#x27;t start by occupying the same space, then deciding that&#x27;s not a valid state and taking corrective action.
评论 #11396168 未加载
评论 #11396204 未加载
评论 #11399845 未加载