My first impressions with Elm

Elm is a domain-specific programming language for declaratively creating web browser-based graphical user interfaces. Elm is purely functional, and is developed with emphasis on usability, performance, and robustness.

Source: Wikipedia

Elm is a functional programming language created in 2012 by Evan Czaplicki for his thesis. The platform is now used in production by a few companies: NoRedInk or Pivotal Tracker.

The idea is to compile Haskell Elm to Javascript to create web site. I wanted to give it a try because:

TL:DR: My expectations are partly achieved: there are not 42 libraries to do the same thing but you still need too much tools around your project. The language being close to Haskell is definitely functional, there is no state (at least they are “hidden”) and the language rely on Message to exchange informations. It feels sometimes a bit of a burden but only because I am a beginner.

Note: I discovered the Awesome List of Elm with all the needed pointers.

First of all I chose the following tutorial www.elm-tutorial.org and the produced code is available on GitHub. I just copy/paste some code while reading the explanation then I started to implement some functionality by myself.

Here are a list of my first impressions:

First of all the compilation and the unit test are lightning fast.

This may be biased since I am currently coding in Scala and its compiler is extremely slow, but it is real pleasure to code.

You don’t have the time to slack off on reddit or hacker news. It seems even faster than babel.

The compiler is really strict

It’s the first time I like a compiler, I usually don’t compliment compiler, yet:

type Msg
    = GeneratePlayer
      | ShowPlayers

update : Msg -> String
update message =
    case message of
      ShowPlayers ->
          "the players are: "

On the landing page, the documentation state “No Runtime Exceptions” and it looks like like they are not lying. I feel like I don’t really need to test that my component are integrating well with each others. Nonetheless, I do need to test my business logic.

The community is small but very active

The community is quite small but really active. Yet it means one things: you just can’t copy/paste your exception and expect to find the answer on stackoverflow. For example, to have a better understanding of the testing framework, I look at the core library tests. However the number of IDE integration is pretty high.

Steep learning curve

The learning curve is pretty steep, especially if you are not familiar with functional programming, Haskell is definitely a plus. At first sight the following expression is not very clear

List.foldr (+) 0 [1, 2, 3]

The architecture was new in many way for me:

The web application is based on a message architecture which is not trivial to implement.

Weird indentation

The code formatting standard for creating the object feels weird

new : Player
new =
    { id = "0"
    , name = ""
    , level = 1
    }

After a few days it actually make sense:

Html in Code, WTF ?!?

I am still surprised by using HTML method in my code, I still don’t have a strong opinion with that feature but I got used to JSX in react. You can find a example in the following snippet.

btnLevelDecrease : Player -> Html Msg
btnLevelDecrease player =
    a [ class "btn ml1 h1", onClick (ChangeLevel player.id -1) ]
        [ i [ class "fa fa-minus-circle" ] [] ]
No interoperability with Javascript

Even if we can use Javascript and Elm in the same webpage, it’s not possible to use javascript library in Elm code. It would definitely break the message architecture with all those awful callback.

Still too many tools needed

This is one of my deception: I was expecting to get rid of npm, bower, webpack, gulp & co but it ain’t that simple:

Damn it’s easy to write unit test

Since all the code is immutable, it’s a pleasure to write unit test: no need to mock, no side effect. The tests are easily understanding like the following snippet from my project

layers: List Player
players = [
    { id="1"
    , name= "toto"
    , level = 1
    }]

tests : Test
tests =
    [ describe "deletePlayer"
        [ test "should remove no player if not in list" <|
            \() ->
                let
                    actual = deletePlayer "3" players
                in
                    Expect.equalLists actual players

I have found two limitations:

deleteRequest : Player -> Http.Request PlayerId
deleteRequest player =
    Http.request
        { body = memberEncoded player |> Http.jsonBody
        , expect = Http.expectStringResponse (\_ -> Ok player.id)
        , headers = []
        , method = "DELETE"
        , timeout = Nothing
        , url = "http://localhost:4000/players/" + player.id
        , withCredentials = False
        }


delete : Player -> Cmd Msg
delete player =
    deleteRequest player
        |> Http.send OnDelete
No “Oh my god, I will only use this from now on” effect

It might be for the best since I have always been deceived after that initial feeling because it would only mean that there is some kind of dark magic going on under the hood.

So far, I like to language and the developer experience but its usage is not widespread enough to be used for my clients. I will nonetheless consider it for my next personal project, It will strengthen my functional programing skills which is always a plus.

Disclaimer: I have only played with the language for 3 days.