Highway
to
Elm
Highway
to
Elm
Jordane Grenat
@JoGrenat
Front-end is dominated by
JavaScript is backward compatible
Biggest advantage
Biggest disadvantage
You can't deprecate things !!! 😱
null > 0 // false
null == 0 // false
null >= 0 // ... true
JS syntax size
Time
ES6
A LOT to learn!
- The language is complex
- Many ways to do the same thing
- Framework choice / learning
- Tooling
Hard to optimize
- Dead code elimination / Tree shaking
- Assets size
- Complex build
Low confidence level
- Minor IDE assistance
- Refactoring is painful
- Slow feedback cycle: runtime
- Dependencies are risky
Elm is a typed functional language to create fast and reliable web applications
Websites and webapps
Domain specific
Statically typed
- Many bugs don't compile
- IDE can help you
- Refactoring is compiler-driven
- Feedback cycle is really fast
No Runtime Exceptions
17K+ LoC
200K+ LoC
Fast
- Everything is pure => optimizations
- Small assets
"Elm has a very strong emphasis on simplicity, ease-of-use, and quality tooling."
Simplicity, ease of use
- Focused on one purpose
- Syntax removal
- Well-thought API
- Compiler helps you
- Explicitness
Quality tooling
- Compiler
- Project starter
- Package manager
- Dev environment
- REPL
- Tests runner
- Doc tool
Great community
See also Building Trust: What Has Worked by Richard Feldman
and What is success? by Evan Czaplicki
Syntax
-- a single line comment
{- a
multiline
comment
-}
Comments
Modules
module Map exposing (navigate)
import Random
import Html exposing (div, h1)
myString : String
myString = "Hello"
add : Int -> Int -> Int
add a b = a + b
Type annotations
myUser : { login : String, password : String }
myUser = { login = "Jordane", password = "passw0rd" }
updatedUser =
{ myUser | password = "S3cur3d" }
-- { login = "Jordane", password = "S3cur3d" }
Record update
let
in
twentyFour + sixteen
3 * 8 + 4 * 4
let
twentyFour =
3 * 8
sixteen =
4 * 4
in
twentyFour + sixteen
let ... in
case myNumber of
0 ->
"Zero"
1 ->
"One"
anythingElse ->
"Nor 0 nor 1"
case ... of
case myNumber of
0 ->
"Zero"
1 ->
"One"
_ ->
"Nor 0 nor 1"
case myStringMaybe of
Just myString ->
"myStringMaybe contains: " ++ myString
Nothing ->
"myStringMaybe contains nothing"
case ... of
myStringMaybe = Just "Hello"
"Hello"
case myList of
[] ->
"The list is empty"
firstElement :: tail ->
"First element: " ++ firstElement
case ... of
myList = ["first", "second", "third"]
"first"
["second", "third"]
What we'll build
The
Elm
Architecture
Model
view()
update()
Html Msg
Elm Runtime
Msg
Html
Event
(new) Model
Program: Sandbox
main : Program () Model Msg
main =
Browser.sandbox
{ init = initialModel, view = view, update = update }
main : Program () Model Msg
main =
Browser.sandbox
{ init = initialModel, view = view, update = update }
type alias Model = { counterValue : Int }
main : Program () Model Msg
main =
Browser.sandbox
{ init = initialModel, view = view, update = update }
type alias Model = { counterValue : Int }
view : Model -> Html Msg
view model =
-- Display view according to model
main : Program () Model Msg
main =
Browser.sandbox
{ init = initialModel, view = view, update = update }
type alias Model = { counterValue : Int }
view : Model -> Html Msg
view model =
-- Display view according to model
type Msg =
Increment | Decrement
main : Program () Model Msg
main =
Browser.sandbox
{ init = initialModel, view = view, update = update }
type alias Model = { counterValue : Int }
view : Model -> Html Msg
view model =
-- Display view according to model
type Msg =
Increment | Decrement
update : Msg -> Model -> Model
update msg model =
-- Return new model according to message and former model
Program: Sandbox
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
{ model | counterValue = model.counterValue + 1 }
Decrement ->
{ model | counterValue = model.counterValue - 1 }
Shuffle answers
shuffleAnswers answers
-- ["Rouge", "Noir", "Blanc", "Vert"]
shuffleAnswers answers
-- ["Noir", "Blanc", "Vert", "Rouge"]
Ask the Elm Runtime to do it!
Effects
Model
view()
update()
Html Msg
Elm Runtime
Msg
Model
Model
Msg
Cmd Msg
Program: Element
main : Program Value Model Msg
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
main : Program Value Model Msg
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
init : Value -> (Model, Cmd Msg)
main : Program Value Model Msg
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
init : Value -> (Model, Cmd Msg)
update : Msg -> Model -> (Model, Cmd Msg)
main : Program Value Model Msg
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
init : Value -> (Model, Cmd Msg)
update : Msg -> Model -> (Model, Cmd Msg)
subscriptions : Model -> Sub Msg
Random
- Take this question
- Get all the answers
- Pick them in a random order
- Put them in the question
Runtime
Generator Question
Cmd Msg
Random
type Msg =
GenerateInt
| IntGenerated Int
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GenerateInt ->
( model, Random.generate IntGenerated Random.int )
IntGenerated int ->
( { model | randomInt = int }, Cmd.none )
Generator Int
Cmd Msg
Advantages
- Great developer experience
- No runtime exceptions
- Great debugger
- Powerful type system
- Great performances
- Great community
Drawbacks
- Opinionated governance model
- Boilerplate vs Explicitness
- Not for every use case
Why use Elm?
- Complex UI / Model
- Frequent refactoring
- You care for bugs
- Easy introduction to FP
- Write better code
Thank you!
Links
Slides : http://bit.ly/elmlang-workshop
Official website: elm-lang.org
The game: trivia-game.surge.sh
Workshop: github.com/jgrenat/elm-workshop
Awesome talks:
- Make impossible states impossible by Richard Feldman
- The life of a file by Evan Czaplicki
Workshop – Highway to Elm!
By ereold
Workshop – Highway to Elm!
Slides for my university Highway to Elm!
- 1,266