I’m struggling to understand how to get the current time with Elm. I would expect that Time.now
would return a Time
or Int
or Float
but instead it is the ever-confusing Task
. I want to use the current Posix time in milliseconds to generate keys for a Dict
when creating new entries. I’m hopeless with this concept.
There is short example of getting time here in official guide: https://guide.elm-lang.org/effects/time.html
I’ve read through that several times but don’t understand how to translate constantly updating every second for just getting the time when I click a button. My problem is not with the Time module per se, but with Tasks in general. I don’t understand the need for them and what they accomplish. When I say “Elm, I want the current time” I expect Elm to return the current time. Instead Elm returns some Task awaiting some other ingredient that I don’t know how to supply.
Here is small example in Ellie about how to add items to Dict
on button press, using current time as key: https://ellie-app.com/3N8Pk6BZy39a1
Functions in Elm are pure functions without any side effects. Only information functions can access is their parameters and nothing else. So it’s impossible to create a function getCurrentTime
in Elm as functions can never access the clock.
Only Elm runtime has access to clock, which is why you need a Task
which gets the time from Elm runtime.
Thank you for the illustrative example, very helpful. I guess I’m still just confused by the need to expose that need for the Task
. Are there any instances in which you would call Time.now
and not perform a Task
of some sort? If not, why not have the Time
module build that in?
No, I don’t think there is any case when you would use Time.now
without Task
.
But there are other use cases for Time.now
than just simply getting current time. For example in my time-syncing app I use three tasks together:
- get request start time (
Time.now
) - fetch time from server (
Http.get
) - get request end time (
Time.now
)
And then I calculate client/server clock offset from these values.
So since there are different ways to use tasks like Time.now
, it makes sense to put all common Task
related code in it’s own package and not complicate for example Time
package with such code, even if that does make simple case of e.g. getting current time a bit more complicated that it needs to be (i.e. must use Task.perform
with Time.now
).
In Elm, all functions must return the same value given the same arguments. Functions that have this property are called pure functions and in Elm all functions must be pure.
Functions like increment
are pure. You can call increment 2
as many times as you want in any context and you will always get 3
back.
The problem comes with functions like rand
or now
. The entire purpose of these functions is to return different values every time they are called. These functions would be useless if they always returned the same value. However, to have functions like that would violate Elm requirement that all functions must be pure.
Elm’s solution is an approach called effects as data. Instead of actually doing the work of calculating a random value or the current time ourselves, we generate a “request” for the Elm runtime to do that work. This “request” (a Task
or Cmd
value) does not immediately execute. Instead it is a piece of data that can be returned, passed around, and transformed. Eventually we pass it to the Elm runtime (by returning it from the root update
function) and the runtime will execute it.
So what does all this fanciness this buy us? Time.now
and Random.generate
now always return the same value (the “request” to the runtime) for the same arguments. Time.now
always returns the same task. We’ve changed non-pure functions into pure functions!
I guess this is a case in which ideological purity is at odds with the secondary goal of ease of use. Thanks for the explanation.
Is your app code public? I’d like to look through it if so. Thanks for taking the time to help me out.
Yes, it’s “time-check” at elm-examples (Main.elm). Live version is here.
Yeah true. But all the good stuff about Elm (no runtime exceptions, easy refactoring, the feeling of “if it compiles it works”) comes from its guarantees. And guarantees have to be absolute or they don’t work. To quote one of Richard Feldman’s talks, “just one drop if urine in a barrel of water gives you a barrel of urine-water”.
The trade-off is that you get some simple cases that feel overly complicated. Time and randomness are the two main ones I can think of.
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.