Richard Feldman said:
main = Arg.list! {} |> List.mapTry Str.toU8 |> Task.fromResult! |> List.sum |> Num.toStr |> Stdout.line!
looking at this, I think it would read better if Task.fromResult had a different name. For example:
main =
Arg.list! {}
|> List.mapTry Str.toU8
|> Task.try!
|> List.sum
|> Num.toStr
|> Stdout.line!
what I like about |> Task.try! is that I read it as "try this Result, and if it Errs out, bail out with an error task, but otherwise keep going with its Ok"
Hmm, I still prefer fromResult
I agree with the consistency of Task.try with how Result.try works
I would say,Result.try is more Task.await than Task.fromResult. I’d prefer fromResult as it’s straightforward with no ambiguity
I actually think the consistency of Task.try and Result.try might be a mistake. Less so now that we have ! though and Task.await is hidden from the users, but I think Task.try and Task.await feel too similar.
I think it is also import to look at how we would use .try in other packages. For example, I would expect List.try to be a List (Result ok err) -> Result (List ok) err.
By that logic, Task.try should really be a Task a err, (Result a err -> Task b err) -> Task b err. Which would actually make Task.try the same as Task.attempt.
That said, I do prefer Task.try over Task.fromResult, especially if there is a ! immediately used. Just not sure the naming fits otherwise.
Also, I think the most important behaviour here isn't the fact we are are turning the result into a task. I think the important behaviour here is that we are propagating the error in a way that makes it feel like we are magically unwrapping the result.
Feels very much like doing:
if error case:
raise exception
So maybe that should somehow influence the naming?
One new option that we have with Task in the standard library, is to replace Task.fromResult with Result.toTask. This is super subjective, but Result.toTask feels more "pipeliny" to me, keeps the literal descriptiveness of the original. Plus I think it might be slightly easier to find in documentation, because a person wondering what to do with this Result value they got someplace will find their answer in the documentation of the Result module.
hm, that would create a circular dependency between the Task and Result modules, which I'd prefer to avoid if possible :sweat_smile:
There’s also Task.result that resolves a task to a result. I think it also makes sense to have symmetry there.
I much prefer Task.fromResult over Task.try. I like that it makes it clear that it is just doing a simple conversion from a result into a task and nothing more
Last updated: Jun 16 2026 at 16:19 UTC