The front-end programming world has been very divided between two major technologies that ruled the way client-based applications must be developed: React and Angular.
For some time now, I have seen a great interest in the community in the Elm language. At first I couldn’t understand the motivations and thought it was more of a hype, but as I delved deeper I saw that Elm is really a fantastic language. It practically forces you to develop the right way and reinforces all the good practices we see today in JavaScript in a natural way.
Elm?!
For those who still know little about Elm, we can summarise it this way:
Elm is a strongly-typed, functional language that compiles for JavaScript, HTML, and CSS.
The main idea is to bring the benefits (and guarantees) of Functional Programming to the Front End.
Elm does not try to have anything to do with JavaScript, unlike the other languages that are compiled for it. It is a completely different language, with its own ecosystem, and you happen to need JavaScript to run in browsers.
Benefits
One of the most talked about points by language creators is that Elm has no runtime exceptions. If you can compile Elm code, you simply will not have runtime errors.
That is, you’ll never see errors like this again:
Uncaught TypeError: undefined is not a function
And this is only possible because of three language features:
- Strong typing
- Immutability
- Null and Undefined do not exist.
Smart Compiler
One of the most surprising points, especially for those who are used to JavaScript, are the compiler error messages. I had never seen anything like it in any other language.
In the example below we made a small mistake. We typed butto instead of button:
1. view model =
2. div [] [ butto [ onClick Decrement ] [ text “-” ] ]
Notice the error message that the compiler returns to us and tell me that it is not absolutely fantastic:
Cannot find variable 'butto'
2| [ butto [ onClick Decrement ] [ text “-” ]
^^^^^ Maybe you want one of the following?
button
Html.button
Best Practices
When we think of best practices in the current JavaScript scenario, we immediately associate it with:
- Functional Programming
- Immutability
- Predictability
- Reactivity
These benefits, which are often associated with the React/Redux combination, come built-in in the language, without having to use any external libs.
Even the creator of Redux admitted that he used Elm’s architecture as an inspiration.
A Small Example
First of all, you’d need to follow the instructions stated in their official setup webpage.
To import modules with Elm, just add import followed by the module name you want.
As we will use HTML in the application we will import the Html module, one of the official modules of the language, like this:
import Html
This way we can invoke HTML module functions, like this:
Html.text 'Hello'
But repeating the module name every time we invoke a function from it can be tiring. We can avoid this repetition by changing the import by exposing the functions we are using:
import Html exposing (text)
text 'Hello'
We can also expose all the functions of a module without having to name each one:
import Html exposing (..)
text 'Hello'
With this we already have the first line of our application:
import Html exposing (..)
Model
Our model will be extremely simple. Since we have a counter, the model will be a simple integer value, initialised with zero:
model = 0
Optionally, we can make model typing explicit by making a Type Annotation, like this:
model: Int
model = 0
If we don’t do the type annotation, the compiler will automatically infer the types.
With this our application looks like this:
import Html exposing (..)
model: Int
model = 0
View
It makes no sense to build an accountant without being able to view it. We then need our view, which will simply be a function that will convert Elm code to HTML.
That is, two buttons: one to increment and one to decrement, and a text element with the counter value.
We can then implement the function that will represent the view like this:
view model =
div []
[ button [] [ text "-" ]
, div [] [ text (toString model) ]
, button [] [ text "+" ]
]
The above code may seem complicated, but let’s demystify it step by step.
In line 1, we are creating a function called view, which takes as our parameter our model. This new view function will receive a div, which is also a function.
The div function takes two parameters:
- The first is a list of attributes (id, class, style, etc.), in our case it will be empty because we don’t need any attributes.
- And the second is a list of child elements of this div.
The children of div will be:
- A button to decrement the counter
- Another div with counter value
- One button to increment counter
Since our model is an Int, we cannot simply use it in the text function, because it expects a String as a parameter. So we convert the model value of an Int to a String.
Now just make the view type annotations explicit.
If we look at the view function, we find that it expects a model as a parameter (which is simply an Int) and returns an HTML result.
But this is incorrect for one small detail:
view: Int -> Html Msg
Later on we will understand this obscure Msg, but I want you to focus on this moment just that the view receives the model and returns an Html.
So our full application looks like this:
import Html exposing (..)
model: Int
model = 0
view: Int -> Html Msg
view model =
div []
[ button [] [ text "-" ]
, div [] [ text (toString model) ]
, button [] [ text "+" ]
]
Type Aliases
A good convention for the Elm community is to create Type Aliases to make it easier to read created type annotations.
In our case, we can create an Alias for the model like this:
type alias Model = Int
That is, everywhere in our application that we are using Int to refer to the model, we can now use Model itself. Making reading a lot easier, especially in large applications.
Updating the application then we have:
import Html exposing (..)
type alias Model = Int
model: Model
model = 0
view: Model -> Html Msg
view model =
div []
[ button [] [ text "-" ]
, div [] [ text (toString model) ]
, button [] [ text "+" ]
]
This is just a brief introduction to the language itself, and its fundamental structures. Go ahead now and try it for yourself. Try improving on the given example by adding an update system for the incrementing and decrementing parts. Have fun!
About the Author
Diogo Souza works as a Java Developer at PagSeguro and has worked for companies such as Indra Company, Atlantic Institute and Ebix LA. He is also an Android trainer, speaker at events on Java and mobile world.