Top 6 ways to make your Elm app crash at runtime

Elm is famous for having “no runtime exceptions” and for the most part, it does a really, really good job! It is possible to write Elm without runtime exceptions, and the majority of users may never see them.

A while ago, I tweeted 9 different ways to make runtime exceptions that I could think of off the top of my head over a series of days. Here’s a little examination of the 6 I have encountered in the wild, and some rules I like to follow to avoid running in to them. I follow these rules to ensure my Elm applications never crash — but sometimes I do it just for fun anyway.

This is true as of Elm 0.18.

Number 1 — Regex

If you go to the Results tab, you’ll see nothing! That’s because Regex.regex crashes when you give it an invalid regex. In this case, I started a group without closing it — which means my Elm app crashed. This crashes on load, since Elm is not lazy for top level values, but if you use your Regex inline, then it won’t crash on load — meaning runtime errors can easily make their way into production.

Click on the results tab, then click on the button and see how nothing changes! This is because the runtime error only happens now when the update function is evaluated. Imagine if this was actually several functions deep! Pretty tricky to figure out.

My rule: only define regexes at the top scope

Number 2 — Arrays

Click on the results tab and you’ll see nothing! This is because of the way the core Array implementation implements things. Internally, it uses a structure based around the number 32 to lay out a nested tree of arrays that allow for fast indexing. You can read more about it by exploring a fixed alternative, called elm-array-exploration by Robin. The original implementation was almost entirely written in Javascript, and the documentation and the author have long vanished, like an old oak table in the night. Robin’s implementation focuses on writing as much as possible in pure Elm — and only using JS for the implementation for the core parts needed.

My rule: never use elm-lang/core’s array if you want things to work. Use elm-array-exploration until it replaces core’s implementation.

Number 3 — function equality

Check the results tab — you won’t see anything. There’s not really much to say about this. Maybe function equality should be supported, maybe it shouldn’t. I’m more of the shouldn’t side, but that’s not really here nor there.

My rule: you probably don’t want function equality. Stick them as values in a dict with an ID of some kind.

Number 4 — Elm is not lazy!

Notice how Maybe.withDefault might look harmless, but actually, if you go to the results, all you’ll get is a page full of blank. That’s because Debug.crash is evaluated when you pass the string to it, and without putting it in a function, it just gets run right away — even though we have a Just!

The fix is to just use a good old case statement instead

case Just 4 of
Nothing -> Debug.crash "This will never happen"
Just x -> x

My rule: never have a Debug.crash that isn’t either in a case statement or a function

Number 5 — not everything should be encoded

Notice that we had to make a new object twice: otherwise Elm uses referential equality and shortcuts this trick. However, I’ve run into problems with this only once or twice — and neither time was shortcutted! I have some more documentation of these data structures here.

My rule: never do ==, toString, etc on Json.Value. Only use functions that look like Json.Value -> _

Number 6 —Invalid Html.Attributes

My rule: make sure you know the Html spec (tongue in cheek applied)

Conclusion

Most of what I make are experiments. I promote both the ideas of getting things done and getting things done the right way.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store