Stream: API design

Topic: Task.forever docs vs impl discrepancy


view this post on Zulip Sam Mohr (Jun 24 2024 at 05:40):

The docs for Task.forever say that it's a function that never returns, but it seems like it does return if the provided task returns an error. I think either the implementation should be changed to actually run forever (a.k.a. ignore errors), or the docs should change to say "It will run forever unless it returns an error, at which point it quits looping" or something to that effect. Here's the source from basic-cli:

## Run a task that never ends. Note that this task does not return a value.
forever : Task a err -> Task * err
forever = \task ->
    looper = \{} ->
        task
        |> InternalTask.toEffect
        |> Effect.map
            \res ->
                when res is
                    Ok _ -> Step {}
                    Err e -> Done (Err e)

    Effect.loop {} looper
    |> InternalTask.fromEffect

view this post on Zulip Sam Mohr (Jun 24 2024 at 05:44):

I was first thinking that it would be best to keep the implementation the same, since people likely already use the function, but then I think the name is actually misleading (for the above reasons). If we keep a function with the same intended behavior, I think we should rename it to something more descriptive. Some suggestions:

Anything better?

view this post on Zulip Sam Mohr (Jun 24 2024 at 05:47):

In the meantime, a Task.forever that actually runs forever would be nice, but changing the signature without changing the name would mean a lot of code might break. It seems like we're still at the "breaking stuff is fine" stage, but I'm not sure if that would be a good idea.

view this post on Zulip Sam Mohr (Jun 24 2024 at 05:50):

All in all, I vote for two changes to the Task interface:
1) Create a new Task.repeatUntilFail function with the signature Task * err -> Task * err that loops forever the same Task until it fails, at which point it returns.
2) Change the signature of Task.forever to Task * * -> Task * * and have it loop forever, ignoring errors.

Feel free to share your thoughts.

view this post on Zulip Brendan Hansknecht (Jun 24 2024 at 05:59):

I would vote for Task.repeatUntilErr or Task.repeatUntilError. Cause it is Task.err that it is repeating until

view this post on Zulip Brendan Hansknecht (Jun 24 2024 at 06:00):

That said, I also think forever is a fine name with the doc saying, repeats forever unless an error ocurs.

view this post on Zulip Brendan Hansknecht (Jun 24 2024 at 06:01):

Don't have much of an opinion about a Task.forever that truly repeats forever. Personally, I would expect to accidentally use it when still expecting errors to fail and then be really confused.

view this post on Zulip Brendan Hansknecht (Jun 24 2024 at 06:01):

Cause my mental model of tasks separates the success case from the error case. So I kinda always expect things to fail on any sort of error.

view this post on Zulip Jasper Woudenberg (Jun 24 2024 at 06:13):

I'm curious, what use case did you have in mind for the function that would truly loop forever, ignoring errors? Closest thing I can come up with is something like a server or game loop, but even that I'd want to be able to stop eventually to quit.

view this post on Zulip Sam Mohr (Jun 24 2024 at 06:13):

Yeah, I agree there isn't much of a use case.

view this post on Zulip Sam Mohr (Jun 24 2024 at 06:14):

You can always just make the error variants empty and use the "return on error" variant

view this post on Zulip Sam Mohr (Jun 24 2024 at 06:14):

So I guess I just propose we rename and re-document Task.forever

view this post on Zulip Luke Boswell (Jun 24 2024 at 06:36):

From this discussion, I think we should keep the current name and just update the docs to be clearer about how it works in the error case. It is true that if there are no errors it never ends, so the happy path behaviour is consistent.

view this post on Zulip Sam Mohr (Jun 24 2024 at 06:37):

@Brendan Hansknecht then I guess the question is whether a slight improvement in function name clarity (I think Task.repeatUntilErr is clearer than Task.forever) is worth breaking existing code. I think it is worth it to get it out of the way, since this function isn't probably used too much.

view this post on Zulip Sam Mohr (Jun 24 2024 at 06:37):

@Luke Boswell do you think it is more clear but not worth the breakage, or it's not much clearer?

view this post on Zulip Luke Boswell (Jun 24 2024 at 06:38):

I'm not convinced it's any clearer.

I'm always happy to break things, but in this case I think the shorter name is better.

view this post on Zulip Sam Mohr (Jun 24 2024 at 06:38):

Okay, I'll keep the name the same for now


Last updated: Jul 06 2025 at 12:14 UTC