Upgrading to Elm 0.19 in early 2019

So, I finally got around to updating this Elm app (for presentations) to Elm 0.19 (along with cutting out a bunch of features so it was a better example app for people wanting to make Elm presentations. The result is at: Elm Present.

I assumed it would be pretty easy. I wasn't doing anything too fancy and had a very small number of dependencies (nearly all core and one Evan-special). It wasn't.

I started out by trying to do it manually, assuming it would be pretty easy. After wasting half an hour, I threw that away and started again with Elm Upgrade.

While this sorted out the elm.json file, it left a lot to do. I already knew about the new String.fromFloat, etc., in place of toString, so those were easy. (I don't buy the rationale here at all! In a frontend-focused ecosystem, making it harder to convert to strings is ridiculous, and String Interpolation is an obvious missing feature)

Keyboard

This was the worst part. I just wanted to do some simple things triggered by particular keys, and basically, all the stuff I was using didn't exist anymore. After much searching and reading of source code to figure out how to do things, I ended up using ohanhi/keyboard to replace the now-removed(?) functionality from the core library.

I'm now using Keyboard.downs KeyDown in subscriptions, with the following message code:

import Keyboard exposing (RawKey)
type Msg
[...]
  | KeyDown RawKey
[...]

The handling and update code looks like this (it was previously using integer keycodes):

keyDown : RawKey -> Presentation -> Presentation
keyDown key presentation =
    case Keyboard.rawValue key of
        "ArrowLeft" ->
            prev presentation

        "ArrowRight" ->
            next presentation

        "Escape" ->
            { presentation | position = At 0 }

        _ ->
            presentation

Animation

This was also super confusing, as nothing worked in the old app due to things being moved/renamed. This, at least, was better documented, and the new API seems fine (albeit pointlessly different from the old one).

I only want to do animations when between slides, so the subscriptions code does this and composes with other subscriptions. (Maybe a Maybe and filterMap would be a nicer solution here?)

animationSubs : Presentation -> List (Sub Msg)
animationSubs presentation =
    case presentation.position of
        At _ ->
            []

        _ ->
            [ Browser.Events.onAnimationFrameDelta TimeUpdate ]

This is the new animation frame delta code; it now passes a Float rather than a special kind of time (which can then be converted). The Float is in seconds. I use it to move slides around (in a relatively nice, interruptible way).

Miscellaneous

The top-level thing has changed, with many new options for SPA-like things. Though I've heard there are significant bugs with some of these at the moment.

I switched to Browser.document:

main : Program () Presentation Msg
main =
    Browser.document
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }

Conclusions

I think it took around 2 hours (though I was watching Netflix at the same time, so maybe that is unfair). But the original app took about five hours to make, so I'm not exactly impressed. It was very frustrating. One wonderful thing about Elm is how the compiler helps you. Well, that doesn't work if a bunch of stuff has been renamed, removed, moved, or massively changed. For what should have been a very simple update, I spent a lot of time Googling, reading source code, and trying things without any real idea if they'd work. I was holding off on upgrading until things settled down, expecting by now that it would be fairly seamless and that problem areas would be well documented. Neither expectation was met.

However, generally, working with Elm is fantastic, and I should emphasize that this update was a rare disappointment. Despite having not looked at the code for ages, I was easily able to get up to speed and make changes.