The Only Runtime Error I’ve Ever Seen In Elm

I’m not exaggerating. After using Elm on and off for the last few years, I have encountered exactly one runtime exception.

Why is this? Elm’s type system, while lacking several abstractions that make functional programming really fun, is quite good at ensuring you don’t mess up. For example, when you case match on some type, the compiler ensures that you cover all cases. Exceptions are avoided in favor of using well-typed solutions like Maybe throughout Elm libraries.

What was the One Exception then? It came about when I was writing a simple flood fill algorithm for my tiny pixel art app PixElm. My floodfill filled in nearby pixels by generating four recursive calls to the neighbors of a given pixel. For large numbers of pixels, too many calls were generated and the program ran out of stack, causing a crash.

fill : Color -> Point -> Model -> Model
fill colorToReplace pt model =
    if getPixel model.pixels pt /= Just colorToReplace then
        model
    else
        placePixel model pt
            |> fill colorToReplace { pt | x = pt.x - 1 }
            |> fill colorToReplace { pt | x = pt.x + 1 }
            |> fill colorToReplace { pt | y = pt.y - 1 }
            |> fill colorToReplace { pt | y = pt.y + 1 }

There it is. The only runtime exception I’ve encountered when writing Elm to date.

Note that this unfortunately doesn’t mean I found zero bugs in my logic…and it also doesn’t mean Elm is perfect or truly has “no runtime exceptions”. Luckily, I never use Debug.crash and I guess I miraculously avoided ever dividing by zero. There are some more obscure ways to cause a crash, which I didn’t run into either. However, if your goal is to avoid runtime exceptions as much as possible, Elm is probably a pretty good place to be (short of not writing code at all).


❮ Sum Types Are Better Than Others
How sum types help us avoid bugs
Why Volleying Is Allowed In Tennis But Not In Ping-Pong ❯
Differences in some of my favorite sports, at scale