Concurrency and the elm architecture

I’ve been exploring how elm deals with concurrency. In my exploration, I made a silly minimal example of race condition: ellie link. Try the following:

  • Let the counters run by themselves and click toggle auto (you’ll see that they have the same value)
  • Disable auto-increment and click increment a bunch, you’ll see it will increment both counters together.
  • While the auto-increment is on, click increment a bunch, then stop the auto-increment. If you are not unlucky, you’ll see that now the two counters are out of sync.

If you are not familiar with the concept of race condition: it happens in programs where the logic depends on the order in which concurrent code is ran. Typically, in a user interface, code triggered by user input is ran concurrently. Wikipedia has a more complete definition: link.

Here, the two counters get out of sync because of the assumption that view always has the most up to date version of Model (which is not the case).

I’m curious as to which steps you would take to avoid race conditions like this one. The blatant error in my code is incrementing racyCount in the view function and then setting the value in update. view shouldn’t have “update logic” in it.

But in real world applications, it’s more complex than that: with bigger Model records and view functions, it becomes hard to distinguish between what is “update logic” and what is “view logic”. It becomes useful to have a more precise concept of “view logic” and “update logic”.

How would you approach that? Did you ever encounter a bug originating from a race condition in elm?

1 Like

I don’t think this is a concurrency problem, but more a misunderstanding of how views work in Elm. Views will only be updated when the model changes and the browsers triggers a redraw. In most cases, after the model is updated the view will be recalculated somewhere within the next 1/60th of a second. The issue that you see in your example comes when the timer fires and the user also clicks the button inside of that window. Your view ends up using an old model to compute the update. The simplest way to mitigate this is to never rely on the model in the view function to calculate updates. Instead create an increment action and do the calculation in your update function. I have forked your example to clarify what I mean.

3 Likes

Thank you for taking the time to reply.

I understand what you mean. This makes much more sense when you know that there can be delay between the model update and the view update.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.