Upgrading to 0.17

Some core packages have been renamed:

So the first thing you want to do is update your elm-package.json file. Here is one that has been properly updated:

{
    "version": "1.0.0",
    "summary": "let people do a cool thing in a fun way",
    "repository": "https://github.com/user/project.git",
    "license": "BSD3",
    "source-directories": [
        "src"
    ],
    "exposed-modules": [],
    "dependencies": {
        "elm-lang/core": "4.0.0 <= v < 5.0.0",
        "elm-lang/html": "1.0.0 <= v < 2.0.0",
        "evancz/elm-http": "3.0.1 <= v < 4.0.0",
        "evancz/elm-markdown": "3.0.0 <= v < 4.0.0"
    },
    "elm-version": "0.17.0 <= v < 0.18.0"
}

The only changes should be in the dependencies and elm-version fields where you need to update constraints. The easiest way to get this all set up is to update elm-version by hand, and then remove everything from dependencies so you can install the dependencies you still need one at a time with elm package install.

Updating Syntax

The major syntax changes are:

feature 0.16 0.17
module declaration
module Queue (..) where
module Queue exposing (..)

Action is now Msg

The Elm Architecture tutorial uses the term Action for the data that gets fed into your update function.

This is a silly name.

So in 0.17 the standard name is Msg.

The idea is that your app is receiving messages from the user, from servers, from the browser, etc. Your app then reacts to these messages in the update function.

-- 0.16
type Action = Increment | Decrement


-- 0.17
type Msg = Increment | Decrement

No More Signal.Address

The most common thing in your code will probably be that Signal.Address no longer exists. Here is a before and after of upgrading some typical view code.

-- 0.16
view : Signal.Address Action -> Model -> Html
view a m =
  div []
    [ button [ onClick a Decrement ] [ text "-" ]
    , div [] [ text (toString m) ]
    , button [ onClick a Increment ] [ text "+" ]
    ]

    
-- 0.17
view : Model -> Html Msg
view m =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] [ text (toString m) ]
    , button [ onClick Increment ] [ text "+" ]
    ]

Any occurance of address just gets deleted. In the types, you see the addresses removed, and Html becomes Html Msg.

You can read Html Msg as "an HTML node that can produce messages of type Msg". This change makes addresses unnecessary and makes it much clearer what kind of messages can be produced by a particular block of HTML.

The Signal.forwardTo function is replaced by Html.App.map. So you may need to make changes like this:

-- 0.16
view : Signal.Address Action -> Model -> Html
view a m =
  div []
    [ Counter.view (Signal.forwardTo a Top) m.topCounter
    , Counter.view (Signal.forwardTo a Bottom) m.bottomCounter
    , button [ onClick a Reset ] [ text "RESET" ]
    ]

    
-- 0.17
view : Model -> Html Msg
view m =
  div []
    [ map Top (Counter.view m.topCounter)
    , map Bottom (Counter.view m.bottomCounter)
    , button [ onClick Reset ] [ text "RESET" ]
    ]

in result

You can see more examples of the new HTML API here.

Effects is now Cmd

If you are working with HTTP or anything, you are probably using evancz/elm-effects and have your update function returning Effects values. That library was a successful experiment, so it has been folded into elm-lang/core and given a name that works better in the context of Elm 0.17.

The changes are basically a simple rename:

-- 0.16
update : Action -> Model -> (Model, Effects Action)
update a m = case a of
    RequestMore -> (m, getRandomGif m.topic)
    NewGif url -> ( Model m.topic (Maybe.withDefault m.gifUrl url), Effects.none )

    
-- 0.17
update : Msg -> Model -> (Model, Cmd Msg)
update msg m = case msg of
    RequestMore -> ( m, getRandomGif m.topic )
    NewGif url -> ( Model m.topic (Maybe.withDefault m.gifUrl url), Cmd.none ) 

The Cmd stuff lives in elm-lang/core in Platform.Cmd. It is imported by default (with import Platform.Cmd as Cmd exposing (Cmd)) to make it easier to use.

Again, very easy changes. The key goal of 0.17 was to manage effects in a nicer way, so in making these facilities more complete, the term Effects became very ambiguous. You should read more about this in the updated Elm Architecture Tutorial which has a section all about effects.

StartApp is now Html.App

The evancz/start-app package was an experiment to help people get productive with Elm more quickly. It meant that newcomers could get really far with Elm without knowing a ton about signals, and it has been very effective.

With 0.17, it has been folded in to elm-lang/html in the Html.App module.

Upgrading looks like this:

-- 0.16 ---------------------------------------
import StartApp
import Task

app =
  StartApp.start
    { init = init, update = update, view = view, inputs = [] }

main =
  app.html

port tasks : Signal (Task.Task Never ())
port tasks =
  app.tasks




-- 0.17 ---------------------------------------
import Html.App as Html

main =
  Html.program
    { init = init, update = update, view = view, subscriptions = \_ -> Sub.none }

The type of main has changed from Signal Html to Program flags. The main value is a program that knows exactly how it needs to be set up. All that will be handled by Elm, so you no longer need to specially hook tasks up to a port or anything.

Upgrading Ports

Talking to JavaScript still uses ports. It is pretty similar, but adapted to fit nicely with commands and subscriptions.

Here is the change for outgoing ports:

-- 0.16
port focus : Signal String
port focus =
  ...

-- 0.17
port focus : String -> Cmd msg

Instead of hooking up a signal, you have a function that can create commands. So you just call focus : String -> Cmd msg from anywhere in your app and the command is processed like all the others.

And here is the change for incoming ports:

type User = { name : String, age : Int }

-- 0.16
port users : Signal User

-- 0.17
port users : (User -> msg) -> Sub msg

Instead of getting a signal to route to the right place, we now can create subscriptions to incoming ports. So wherever you need to know about users, you just subscribe to it.

You should definitely read more about this here.

JavaScript Interop

The style of initializing Elm programs in JS has also changed slightly.

Initialize 0.16 0.17
Embed
Elm.embed(Elm.Main, someNode);
Elm.Main.embed(someNode);
Fullscreen
Elm.fullscreen(Elm.Main);
Elm.Main.fullscreen();
Worker
Elm.worker(Elm.Main);
Elm.Main.worker();