Elm/core runtime exception via bad usage of Cmd.batch

Hi folks, I just want to give a heads-up so that you perhaps don’t fall into the same problems as I did :slight_smile:

The function _Platform_gatherEffects has issues when given a deep Cmd.batch bag (no issues with wide one, it seems): see Ellie. (Change between woke and broke inside init to illustrate the two behaviours).

Deep:

Cmd.batch [cmd, Cmd.batch [cmd, Cmd.batch [cmd, .......]]]

Wide:

Cmd.batch [cmd, cmd, cmd, cmd, cmd, ...]

This only affects Chrome for me, not Safari. (Perhaps Safari has just higher stack frames limit and would crash later?). The limit seems to be around 4.4k layers.

Now this is admittedly a stupid way to construct Cmds, but it does come up naturally as a solution to some problems, eg. if you have a high-level Effect type that you later convert to a List (Cmd msg). A function to interpret one Effect might look like interpretEffect : Effect -> Model -> (Model, Cmd msg), and multiple: interpretEffects : List Effect -> Model -> (Model, Cmd msg). Now they might depend on each other (how do they change the Model?) so you can’t just concatMap stuff together, you need to thread it through with List.foldl. That’s where the deepness of the resulting Cmd bag comes from. Send 10k effects to interpretEffects at once and you have a runtime exception.

So, while this might be classified as a bad usage of Cmd.batch (and indeed in our app we chunk the lists given to interpretEffects to lists of ~800 items each), perhaps the _Platform_gatherEffects function could be changed to allow for it?

4 Likes

For some reason V8 has a call stack limit somewhere around 11,000 calls, whereas SpiderMoney and JSC are somewhere closer to 40,000 so you are much more likely to hit this error in Chromium-based browsers.

I think _Platform_gatherEffects can probably be implemented with a hand-rolled stack and a while loop instead of being recursive if this turns out to be a common problem for folks.

6 Likes
i = 0; try { (function r() { i++; r() })() } catch { i }
Environment Stack limit
Chrome 90 13910
Firefox 89 10741
Safari 14 39905
Node.js 14 15073
Node.js 16 13403

Measured on macOS.

3 Likes

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