If this were JavaScript,
and we wanted to represent the state
where we are waiting to get the current time,
we might write this init function:
init : ( Model, Cmd Msg )
init =
( { time = null }, Cmd.none )
But Elm doesn’t let you
set any old variable to a “nothing” value like this.
The ability to do this in JavaScript
is by far the greatest source of bugs
in JavaScript programs.
When a variable that you expect to hold a value
actually contains a “nothing” value like null or undefined,
your program crashes
with an “undefined is not a function” error.
By preventing you from setting any variable to null,
Elm can guarantee that this kind of error will never happen
in your Elm programs.
But of course, sometimes you really do have “nothing”!
Until we are able to get the current time,
our program simply can’t tell what time it is.
To represent this, Elm has the Maybe type:
type Maybe something
= Nothing
| Just something
(Don’t add this type to your program! It’s already built into Elm.)
A Maybe type represents
a value that is either not present (Nothing)
or present (Just something).
Whenever you use a Maybe,
you get to choose what the something type is.
In our program,
we have need of a value that is either “nothing” or
“just” a Time value.
So what we want is a Maybe Time.
Let’s update our Model type
to contain a Maybe Time instead of a Time:
type alias Model =
{ time : Maybe Time }
Now we can get our init function to compile
by setting the initial value of the time field
to Nothing:
init : ( Model, Cmd Msg )
init =
( { time = Nothing }, Cmd.none )
Compile and run the program
to make sure everything is working.
Our view function will display this initial value (Nothing).
Since this doesn’t look great,
let’s improve our view function a little
to better handle this “nothing” case.
We can use a case statement
in our view function
to handle separately the different possible values
of our Model.
Since our program only contains a Nothing value so far,
let’s start by handling that:
view : Model -> Html Msg
view model =
case model.time of
Nothing ->
text "Loading…"
Save and run this,
and the compiler will tell you
that you haven’t accounted for all possible values of model.time.
We have told Elm that model.time is a Maybe Time,
so it requires us to handle every possible value of that type.
Again, Elm is making sure that
our programs will never crash as a result of a value
being something other than we expect it to be.
The error message says that
the value we have failed to handle is Maybe.Just _.
So we could add this branch to our case statement,
using the previous code we had written to output the time:
Maybe.Just _ ->
text (toString model.time)
This is a little more verbose than necessary, though.
Elm automatically makes all values in the Maybe module
available to us in every module that we write.
So instead of Maybe.Just, we can just say Just:
Just _ ->
text (toString model.time)
That underscore (_) represents the Time value
that is wrapped in this Maybe type.
The underscore tells Elm that
we aren’t interested in this value.
We’ll come back and tweak this
once we have an actual Time value
for our program to display.
For now, our view function should look like this:
view : Model -> Html Msg
view model =
case model.time of
Nothing ->
text "Loading…"
Just _ ->
text (toString model.time)
Run the program and confirm that it shows “Loading…”.
Now we’re ready to get back to the task of fetching the current time.