DEV Community 👩‍💻👨‍💻

Alex Esoposting
Alex Esoposting

Posted on

Elm: a good frontend language?

Recently a friend recommended me Elm, a pure functional language for developing web applications. I'd like to compare it to JavaScript and show how the functional paradigm can work in practical applications.

If you need a refresher on what functional programming is check out my previous blog post.

Still just JavaScript

Everything is JavaScript...

JS is the only* language standard that is supported by all major browsers and allows for interactive apps. If you want something except from a static HTML you need to use JS. To write an app in another language you need to compile it to pure JS, like many web languages do. Most of them, like TypeScript, are based on JS and offer limited improvement over JS problems. Elm is something entirely different, having no trace of JS's imperative syntax and error prone type coercion, but still compiles to JS in the end to be run by the browser.

*Web assembly is starting to gain popularity, but it's still in developement

No runtime errors

Everything works

By being a pure functional language Elm can guarantee that no matter the time of day, the randomness or the user input, the app will always be ready for whatever comes and will process it without breaking. That doesn't mean any input is valid, just that invalid input will produce error values, which must be explicitly handled in the code or else it won't compile.

Let's take string to number conversion for example. In JS there are multiple ways of doing it: Number(x), parseInt(x), +x among others. All of them return a value of type "number", but they can actually output what is literally Not a Number, and in case of +x they may even just silently ignore invalid strings and return 0. This may lead to some problems in later stages of the program which will be hard to debug because of those silent errors. Solutions to this include a separate check if the string is numeric, which arguably should be a part of the parsing function, and checking for NaNs every time you handle a "number", which should not be necessary because NaN is Not a Number.

In contrast, Elm's String.toInt function returns a Maybe Int type, which can have values Nothing or Just Int. This is an explicit sign: "Something can go wrong here and requires handling!". This value can be then passed along as Maybe Int, or it can be branched on and some handling can be done in case of Nothing, and in case of Just Int just the Int portion can be returned. In fact this pattern is so common that there already are functions for handling Maybe values, the most obvious one being withDefault which takes a default value and substitutes it in case of Nothing. This is again explicit and allows more control over the behaviour of the process instead of silently passing erroneous values and creating an undebuggable mess.

The Elm Architecture

That apparently everyone uses?

Being a pure functional language Elm can't have functions that rely on data outside their inputs or change data outside their outputs. This means working with time, randomness, user input and DOM shouldn't be possible to implement. Elm solves this problem in a very elegant way: you don't write the entire application. It has a runtime system, and your job as a programmer is to provide this system with three things: the initial application state represented in Elm values, a function from state to DOM that will be displayed to the user, and another function from the state and messages that the user may send to a new, updated state. The runtime then renders the page using the initial state and the view function and handles any user interaction by sending appropriate messages that you defined to the update function. All impurity is abstracted to the runtime, so the user can stay in the pure language of Elm.

There are multiple benefits from this. First of all getting to stay pure guarantees no runtime errors. All the input data comes as messages that you defined and are forced to handle in the update function. Pure functions also benefit heavily from compiler optimisation and caching results: even though the view function is called after every update the code is compiled to only calculate parts of the page that changed which keeps the system efficient.

The Elm architecture also serves as a good design pattern that makes thinking about your code easier. It makes you make a model - a representation of the application state in terms of in-language values - and consider what states your app can be in and what can change about it. It forces you to consider all transitions of this state: what to show the user when the additional content loads? How to react when it fails to load? All this is turned into messages that have to be handled or the code doesn't compile. According to the Elm website many JS frameworks and other application languages have adopted the Elm architecture, more or less openly. It's a design pattern that any language can benefit from.


I like Elm

I hate JavaScript and believe that it's a fundamentally badly designed language, so in my personal projects I have been going out of my way to minimize its use. Elm offers a much better designed alternative despite also having flaws. I can't say about enterprise use, but I definitely recommend Elm for the interactive components of your pages, and If you want a taste of it I will be showing how I designed the online timelapse visualisation for one of my projects in my future posts. Stay tuned!

Top comments (0)

🤔 Did you know?

🗺 We put together some guides that include some of our favorite content on DEV. Check them out here.