A little down to earth evaluation of Elm

Petr Huřťák
6 min readAug 29, 2016

This is reaction to the 10 reasons why you should give Elm a try article . I recommend you to read it since it provides nice introduction to the features of the language. But as with any of these articles that praise particular technology, they usually don’t tell you about things that are not so great. So I just took these 10 reasons and added some “not so good” comments to them.

1 — Elm is fast and easy to learn

The docs are nice but lots of times they are very sparse, more examples would be nice. Eg. they tell you the type of Time.now and what it does, but there is no example of how to wire it up in your app, which is nontrivial task for beginner.

The official guide, at the time when I read it, contained a lot of syntax errors in the examples. It is probably much better now, but it still seems quite sparse and not going deep enough. Especially about how to structure your app, there are only 2 short examples, so you are left with learning on your own by browsing other people’s code.

Generally anything other than simplest examples are missing from the official documentations/guides. Also recently there were decent breaking changes which made lot of the material on the internet outdated.

Elm might be easy but ATM the learning material does not provide fast way to learn the language.

2 — Elm syntax is compact and expressive

Semi-official style guide uses a lot of newlines, The Elm Architecture requires decent amount of boilerplate.

I don’t really see this as a problem, but I would not call it compact.

3 — Pipes are beautiful

Yes they are! It is much nicer and cleaner way to do chaining than what is happening in JavaScript world.

Btw github.com/mindeavor/es-pipeline-operator

4 — The Elm Architecture (TEA) is the current best way to do front end development.

Pretty much agree.

5 — Elm documentation is wonderful

Not quite there yet, see point 1.

6 — Forget about runtime exceptions

Exceptions are inexistant

Again, not quite there yer, there is at least one compiler bug that I know of, that bit me twice, and produces runtime exception.

7 — Fast to compile, fast to execute

Maybe I produced some code which compiler doesn’t handle well, but mid sized 7k LoC program takes about 3–10s to compile, and I am just talking about the incremental recompilation which compiles only whatever changed, not the whole program. If Elm did not have incremental compilation, compile time speed would be unbearable.

I don’t have the fastest computer, but this definitely doesn’t seem fast.

8 — Everything is a pure function, so every test is a unit test !

If you are used to Capybara or PhantomJs, you can just … forget about all that

I guess this talks about selenium tests? Lots of times everything compiles and unit tests pass and your program still doesn’t work as expected, because you forget to wire something up or update something in the update function. So I wouldn’t say Selenium tests are thing of the past. But on the other hand, tracing & fixing these bugs is really easy.

Testing is definitely much easier and nicer than in JavaScript.

9 — Elm is used in the best front end intensive projects I have seen

This is just a massive overstatement, there are way more complex apps in the JavaScript world, which isn’t really surprising when we take into account how much older JavaScript is.

I never saw this level of ambition in vanilla JavaScript apps.

Really?

10 — Elm is fun

Can’t argue with that :)

Other observations

The bad

Biggest pain with Elm? Probably type mismatch errors, when you have bigger models and you are somewhere deep in your model/functions, errors can be very confusing. You see what type it expects and what is passed into it, but it is sometimes very hard to figure out why the thing you are passing in, is different from what it expects. And since you can’t really put breakpoint in your program, so you could step through and see where exactly the wrong data happened, you are just left to stare at the screen trying to figure it out.

Elm tries to provide abstraction over the web platform and it’s APIs, but it’s abstraction is not finished. Do you want to change document.title? You gotta use JavaScript. Do you want to focus some input element? You gotta use JavaScript (edit: you can do that now with elm-lang/dom). This is getting better and better with each release, but if you are writing bigger app, there is very good chance, that you will have to write JavaScript anyway. On the other hand, the JavaScript part will be probably somewhere in the 1–5% LoC region, so it’s not that big of a deal.

Errors can also be very indirect, suppose you have view, that takes model, and that view calls 2 other functions, that also use the model. In function 2 you have type mismatch but the compiler can be complaining about misuse of model in function 1. These errors are very frustrating and costly (time wise) to debug. If you do not use type annotations, it gets even worse as the scope of reported error gets even wider.

Here is the example of the indirection I am talking about. Suppose you have super simple program which has a model (integer), and it prints that integer into view.

import Html
import Html.App
type Msg = NoOp
type alias Model = Int
main =
Html.App.beginnerProgram
{ model = 0, view = view, update = \msg model -> model }
view : Model -> Html.Html Msg
view model =
Html.div [] [ Html.text model ]

When you try to compile it, it produces following error:

-- TYPE MISMATCH ---------------------------------------------------The type annotation for `view` does not match its definition.11| view : Int -> Html.Html Msg
^^^^^^^^^^^^^^^^^^^^
The type annotation is saying:
Int -> Html.Html MsgBut I am inferring that the definition has this type: String -> Html.Html a

This might lead you to think, that there is something wrong with the data you are passing into the view function, but the real error is, that the text function is expecting string instead of int. But that text function is not even mentioned in given error. As your program and model grows, it gets worse.

If you don’t have type annotations the problem is even worse as the reported function is further away from where you really made a mistake:

-- TYPE MISMATCH ---------------------------------------------------The argument to function `beginnerProgram` is causing a mismatch.8|   App.beginnerProgram 
9|> { model = 0, view = view, update = \msg model -> model }
Function `beginnerProgram` is expecting the argument to be: { ..., view : number -> Html.Html a }But it is: { ..., view : String -> Html.Html a }

The good

The Elm Architecture, which is like a web framework, along with static typing, makes writing bad spaghetti code much much harder than in JavaScript.

Package manager which enforces semantic versioning (based on type definitions of module’s public API) is just so cool.

One of the nicest things about Elm is that it provides most of the things, that you would want to make web apps, out of the box. You got a great language than wasn’t designed in 10 days, and that doesn’t have lot of baggage that JavaScript has accumulated over the years, you got a great standard library, and you got The Elm architecture (which is basically state of the art web framework). So compared to JavaScript world, you have really nice all in one package for building web applications.

If you wanted to do that in JavaScript you would need:

  • React for views
  • Redux for state management
  • react-redux to wire these two
  • Lodash to have some decent standard library
  • bunch of polyfills
  • Webpack to bundle your app
  • Babel to compile ES6/ES7 to something current browsers can handle
  • Babel to compile non-standard jsx syntax into function calls
  • Flow/TypeScript on top of that, so you have some type safety

You will probably have to spend days, if not weeks, on configuring and making sure these dependencies work with each other. Then, when you start working on different project, the mixtures of libraries used are completely different, so you have to learn a lot (again) before you can start making any changes.

Also you aren’t really writing JavaScript anymore, but some super-set (Flow) of that language, along with custom syntax extensions (jsx). At this point you are probably wondering, if it wouldn’t be better to became a farmer and have a simpler life. Or if it wouldn’t be simpler to just start a clean slate with something entirely different, like Elm.

Conclusion

  • Just wanted to give a little more down to earth look at Elm, than the 10 reasons why you should give Elm a try article provided
  • Elm is pretty good, but it is not quite there yet
  • You should give Elm a try

--

--