Trying out Elm

I’ve been out of the front-end game for a while, and decided to dip my toes back again after roughly 2 years of little-to-none JavaScript. So many things happened in the meanwhile! React, Redux, Flux, Om… What should I use to get back on track?

As I’ve been dabbling a lot in Elixir and Phoenix space, I saw in the community a growing interest for Elm, a functional language that compiles to JavaScript.

So, I’ve decided to use Elm as the gateway back into the browser world, and recently started to experiment with it. I’ve tried to push my understanding to its limit, to see if the hype was warranted.

The rundown

Elm takes a completely clean break from JavaScript, despite compiling to it.

A few characteristics of Elm:

  • Statically typed, with union types being at its core
  • Completely immutable
  • Purely functional (there is a specific part of the standard library dealing with side effects)
  • Very cleverly designed interoperability with JavaScript
  • No non-sense tooling: the compiler is called elm-make, the repl elm-repl, etc.

The Architecture

In the Elm community there’s a standard way of setting up applications that emerged. It’s called, unsurprisingly, The Elm Architecture. I suggest you give it a read. But what is it all about?

  • The application has three main elements: Model, View, and Update.
  • Data flows uniderectionally: you setup events in the View, those will be processed by the Update, which will modify the Model. When the model changes, the views will be re-rendered.

This pattern, conjoined by fact that the model sits in a single place, allows for some spectacular tricks, my favourite being the time travelling debugger.

Type system

One of the things that I struggled the most while getting up to speed with Elm was its type system. The reason being, all functions can be automatically curried. Let’s see an example from the repl:

> hello name location = "Hello, " ++ name ++ ", from " ++ location
<function> : String -> String -> String
> hello "Alessandro"
<function> : String -> String
> hello "Alessandro" "London"
"Hello, Alessandro, from London" : String

So, what’s going on here? I defined a function, hello, that accepts two parameters, and returns a string. This emerges from the notation, <function> : String -> String -> String. But what happens if we pass only one parameter of the two? The repl says, <function> : String -> String, meaning we’re getting back the partially-applied version of hello, now accepting a single string, and returns a string.

As you can see, the compiler does an outstanding job in inferring types and gives you amazing hints when something is not quite right.

The type annotation for `myMethod` does not match its definition. - The type annotation is saying:

    String -> String -> String

But I am inferring that the definition has this type:

    String -> String -> Int

While dealing with the types can sometimes be daunting, NoRedInk reported no runtime exceptions on their Elm code, since they deployed it in production. Not many companies dealing with front-end can match that sort of claim, I’m sure.

Also, the compiler is extremely fast; the feedback while developing is never a hinderance, as you instantly know what to fix.

“Infinitely nestable”?

The claim that mostly got my attention was this:

The Elm Architecture is a simple pattern for infinitely nestable components

Intrigued, I set out to create a Trello “clone”, Trellex, using Elm on the client and Phoenix on the server. The initial model was as follow:

I have a Main module where the application gets initialised. The model is a Board, which has many Lists. A List has many Cards.

The difficult bit is the fact that any event, wherever it’s been triggered, will go through the update function you define when starting the application. Specifically, I have 5 layers to traverse back and forth when the event happens: after the event reached the Main I had to ask each individual module how to update their respective sub-model. Setting up all the plumbing in place was very complicated.

In the end I changed the modelling completely, having all the sub-models directly available from Main, and that actually made the application a lot easier to grok.

Perhaps it’s just me not understanding the correct way to deal with this. This could also be related to the language still to reach version 1.0: best practices and patterns have yet to be set in stone.

tl;dr

Elm delivers on the promise to provide with a super-safe way to build front-end applications. The ramp-up time can be high as there’s a lot to learn, especially if you’re not used to functional programming, or strict type systems. That said, I think the advantage of not having to with good ol’ JavaScript’s quirks (albeit ES2015 improvements are tangible), is great value.

There is certainly lots of work I need to do to fully understand the language potential, but so far it’s been a great experience.

More Reading
Older// About me
comments powered by Disqus