
This is Part 1 in a series about Elm for JavaScript Developers. I've
been programming in JavaScript for a while, and hearing people speak so highly
about Elm inspired me to give it a try! Studying Elm has raised several
questions about this language. The idea of this text is to introduce Elm to
JavaScript developers like myself.
If you're reading this, you're probably aware of what Elm is, but let's go overt it. Elm is a functional language that compiles to JavaScript. It is a
young language, created in 2012 by Evan Czaplicki as his thesis.
In this blog series, we will compare Elm with JavaScript. Today, we will
analyse some of their unique features and illustrate the differences between
them.
Let's do a Hello World in Elm to get started!
mkdir hello_world
cd hello_world
vim HelloWorld.elm
We will create a basic Elm module that outputs Hello, World!
import Html exposing (text)
main =
text "Hello, World!"
We want to generate an HTML text node, so we import the Html module and expose
its text function.
We can use elm-reactor: an interactive development tool that makes it
easy to develop and run Elm applications:
elm-reactor
Now that the reactor is running, we can visit http://localhost:8000 in our
browser and see the result: Hello World on the screen!
Elm has an elm_package.json file which is similar to the package.json file
that node uses. Here is ours:
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "5.1.1 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0"
},
"elm-version":
"0.18.0 <= v < 0.19.0"
}
elm creates an elm-stuff folder to store its dependencies and build
artifacts in. This is similar to the node_modules directory in JavaScript.
Now that we have created our Hello World App, let's look at the differences
between both languages.
Syntax
For a JavaScript developer, the first thing that comes to mind when you see Elm
code is the syntax. You’re probably thinking Elm syntax is really weird,
because it looks nothing like JavaScript.
The Elm site has a quick Syntax Guide to help
you understand the syntax.
Let's look at some differences:
Functions
Elm functions rely on whitespace rather than commas and curly brackets. The
return is implicit. There is no return keyword.
sum a b =
a + b
In this sum function, you can see:
- There is no return keyword
- It doesn't use commas to separate the parameters
- There is an equal sign after the params
Variables and Types
Elm is strongly typed, but it has type inference. This means you don't need to
say that a variable is a number or a string - if you use it like one, Elm can
figure it out.
In Elm we can create union types which means the type can have one of the
described values.
type Animal = Elephant | Horse | Cow
In our case, Animal can be an Elephant or Horse or Cow.
In Elm we can also use Type
Annotation. This is an
optional feature, although highly recommended. You can see it below:
sum: Int -> Int -> Int
sum a b =
a + b
A type annotation should be written right above the function definition. In our
case we have sum: Int -> Int -> Int as a type annotation. It means our function
receives two Int and it returns Int.
DOM
Later we will have an episode just to talk about how Elm manages the DOM. For
the moment, just keep in mind Elm uses a Virtual DOM system, like React. Elm
does not mutate the DOM directly as vanilla JavaScript might.
If you use vanilla JavaScript or even jQuery you can directly mutate DOM
elements without using a representation of it.
To represent the DOM, Elm uses plain old
vanilla
functions. If you have used React, this would be similar to
JSX.
If you want to get a better idea of how fast Elm renders HTML, check out this
blog post from Evan.
Compiled vs Interpreted
Elm is a compiled language. JavaScript is an interpreted language.
In Elm if you have a function that receives two numbers and you pass two
strings, it won't even compile. Elm has a static type system. All the types are
discovered at compilation time.
Let's use the sum function above. We're going to pass two characters rather
than numbers. Let's try to compile that:
Detected errors in 1 module.
-- TYPE MISMATCH ---------------------------------------------------------------
The 1st argument to function `sum` is causing a mismatch.
9| sum '3' '2')
^^^
Function `sum` is expecting the 1st argument to be:
number
But it is:
Char
Yay! The Elm Compiler <3
Here we can see the Elm compiler saying TYPE MISMATCH. It expected a number
but we passed a Char.
Let's try this in JavaScript. We're going to pass two numbers first and
then we will pass two strings.
function sum(a,b){
return a + b
}
console.log(sum(3,2))
// => 5
console.log(sum('3','2'))
// => '32'
For the first call, by passing only numbers, we got the correct result, as we
expected it. With the second call, by passing two strings, we got: 32! JavaScript has
concatenated our two strings.
The Elm compiler is really good at telling us what we should do or what we meant to do.
It's really good to have someone helping
us like the Elm compiler.
Having static type checking means we don't have to have those errors at
execution time. We can completely avoid them in compilation time.
Type correctness does not guarantee program correctness. Just because we have our Elm compiler “helper” doesn’t mean you don't need to test your code. A compiled and static typing language doesn’t magically produce a great app.
Show me the code
We will create a simple Elm app that checks if a number is odd or even. We will
have a button to increment this number and once we increment or decrement the
number, the view will update and say ODD
or EVEN
.
Let's do it.
module Main exposing (..)
import Html exposing (beginnerProgram, div, button, text)
import Html.Events exposing (onClick)
type Msg
= Increment
| Decrement
main =
beginnerProgram { model = model, view = view, update = update }
model =
{ quantity = 0 }
update msg model =
case msg of
Increment ->
{ model | quantity = model.quantity + 1 }
Decrement ->
{ model | quantity = model.quantity - 1 }
checkNumber n =
if ((rem n 2 == 0) == True) then
"EVEN"
else
"ODD"
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [] [ text (toString model) ]
, div [] [ text (checkNumber model.quantity) ]
, button [ onClick Increment ] [ text "+" ]
]
You can check this code on Ellie. Ellie
is a pretty good Elm live editor.
In this example, we are using Html.beginnerProgram, you can check out more about
it in the Elm documentation. checkNumber is the function that checks if a
number is odd or even, and returns a string, saying ODD
or EVEN
.
Once you increment the number, it calls the checkNumber function and the
result will be on the screen.
This is Part 1 on Elm for JavaScript developers.
Interesting Elm Videos
Resources