That’s how quickly I initially dismissed Elm when I first heard about it a couple of years ago, mostly because I was mentally likening it to CoffeeScript, a language which I don’t mind saying I wasn’t a big fan of. And I imagine I’m not the only person to make that mistake, so I figured I’d write a quick post about why I’ve ended up going all-in with Elm, and why I think the language deserves your time.
So here are the highlights:
biggest game in that particular town
● Everything is immutable
Elm makes this a lot easier because it just doesn’t give you the tools to mutate anything outside of the function that you’re working in, and wherever a constant needs to be updated inside a function, a new constant is created, rather than overwriting the old one. This ensures that functions will always have the same outputs when given the same inputs (another important principle of FP), and it also makes your code inherently testable. You don’t have to worry about accidentally braiding your code together because you just don’t really have that ability.
● Every function has a return value
Elm doesn’t give you the option to get yourself into this mess. Every function in Elm acts as an expression (which, as mentioned earlier, can’t control anything outside of itself), and returns the value of that expression (consider the difference between having return statements inside an “if” block vs just actually returning the “if” block in JS). The effect this has on the readability of your code is fantastic — you know that no matter what, you already have a base idea of how functions need to be used.
● Every function is auto-curried
multiply 2” (Elm). For my money, the Elm code is a lot cleaner and simpler to understand.
● Types, and type annotations
when you’re looking at a JS function that you haven’t written (or even one you have written), you don’t necessarily know what you’re going to see there. It may or may not be using JSDoc to document its input and output types, and if it is, it may or may not be up to date, and there’s no guarantee that everything else will be documented even if the function you’re currently looking at is. Maybe you’ll find that TypeScript is being used on this project, and again the type definitions may or may not be up to date (seeing as TypeScript will still compile for you even if the types you put in aren’t what you said they were going to be). Or maybe the development team is really into coercion and intentionally doesn’t care about types wherever they don’t strictly have to.
Elm is strongly-typed and has fantastic support for type annotations. Annotations appear above functions as easily-readable statements; for example, for the “multiply” function mentioned earlier, the type annotation would be “multiply :Int -> Int -> Int”. If that looks weird, remember what I said about auto-currying. You can read that annotation as “takes two integers and returns an integer” (since the last value will always be the return value), but what it’s really saying is “takes an integer and returns a function that takes an integer that returns an integer”; hence
the same symbol being used for both parameters and the return value. Annotations are evaluated by the compiler, so if you write a function and get its type annotation wrong, you will know about it when you try to compile your code,
by way of a very easy to understand compilation error. And if you don’t write an annotation for your function (remember I said they were optional — although I’ve yet to see anyone writing Elm and not using them personally, for good reason), the compiler will tell you what your annotation should be, so you can literally just copy and paste it if you’re unsure. You can also create your own types by way of type aliases, so your annotations can be even more readable if you create type aliases for things that are relevant to your application. For example, you might be writing an e-commerce application that has a “Cart” which contains “Items”, making your codebase even easier to understand to anyone who is unfamiliar.
● The compiler
I’ve touched on this already, but Elm’s compiler is incredibly useful; to the point where you find yourself with a lot of confidence that you know your application is working as you expected as long as it’s compiled. It also makes the language a lot easier to pick up, because you as you’re taking your first steps, the compiler will be actively trying to help you sort your code out. As you can tell, I’m really into Elm, and I think it has a bright future. It’s fun (to the
point where I frequently find myself finishing bits of functionality before I feel mentally “ready” to be finished!), and refreshing, and it has a strong and supportive community behind it. And to be honest, it’s nice to have a genuinely viable alternative to JS for the front-end. Don’t get me wrong, I love JS as well; the tone of this post’s comparisons between Elm and-and JS is only the way it is because in my opinion, Elm compares so favourably in every instance. That’s why I’m not currently spending any time writing anything other than Elm for front-end development
anywhere I don’t have to.
There is a lot more to love about Elm than I’ve covered here. If you’re interested in finding out more, I’d highly recommend you start with Richard Feldman’s excellent “Introduction to Elm” talk, which you can find here: https://www.youtube.com/watch?v=zBHB9i8e3Kc2
By David Nimmo (@k_fistman)