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.