I'm not sure, but I think this could be a bug.
When trying to use try
when using a platfrom that still uses Task
I get weird behaviour.
When trying to do something like this:
validateName : Str -> Result {} [NameTooShort, NameTooLong]
runValidation = \name ->
name |> validateName |> try
# do some stuff
Ok {}
I get an error:
── STATEMENT AFTER EXPRESSION in ./try.roc ─────────────────────────────────────
I just finished parsing an expression with a series of definitions,
and this line is indented as if it's intended to be part of that
expression:
15│ name |> validateName |> try
^^^^^^^^^^^^^^^^^^^^^^^^^^^
However, I already saw the final expression in that series of
definitions.
This works fine with a variable assignment:
validateName : Str -> Result {} [NameTooShort, NameTooLong]
runValidation = \name ->
_ = name |> validateName |> try
# do some stuff
Ok {}
But I get a warning:
── UNNECESSARY DEFINITION in ./try.roc ─────────────────────────────────────────
This assignment doesn't introduce any new variables:
15│ _ = name |> validateName |> try
^
Since it doesn't call any effectful functions, this assignment cannot
affect the program's behavior. If you don't need to use the value on
the right-hand side, consider removing the assignment.
And when I use {}
:
validateName : Str -> Result {} [NameTooShort, NameTooLong]
runValidation = \name ->
{} = name |> validateName |> try
# do some stuff
Ok {}
The formatter deletes the {} =
and we are back to the first case with an error.
When trying the same thing in a platfrom that uses the purity inference, this code works:
validateName : Str -> Result {} [NameTooShort, NameTooLong]
runValidation = \name ->
name |> validateName |> try
# do some stuff
Ok {}
But I get a warrning:
── LEFTOVER STATEMENT in ./app.roc ─────────────────────────────────────────────
This statement does not produce any effects:
14│ name |> validateName |> try
^^^^^^^^^^^^^^^^^^^^
Standalone statements are only useful if they call effectful
functions.
Did you forget to use its result? If not, feel free to remove it.
────────────────────────────────────────────────────────────────────────────────
When all platforms migrate to purity inference then only the last example will be a valid issue.
Yeah, bug
Compiler doesn't understand that try kinda has a side effect in that it will return on error
As such it is valid as a standalone line
Kind of a bug? Brendan is right with respect to purity inference, in that try
is a purity inference-specific keyword that can't yet work for pure tasks, even though it should. I'll make an issue later
But for Task
code, try
won't work because it tries to early return an Err err
, not a Task.err err
So you should continue to use ?
for Task, and try
only with purity inference
The function is still the same and it is also returning a Result
not a Task
- only difference is that the platform is still using Task instead of purity inference.
IDK why this matters.
Yes, you're right, I had too much context in my head to get outside of my head, but it wasn't as useful for you in particular
So what I said is the case for trying Results in Task functions
Your code is a bug
To implement the fix is a little tricky because we currently just desugar try
to a when expression and don't see try
AST nodes. we could probably look through each pure expression and if there are return
expressions, then we allow them.
Yeah, I think those should be allowed as long as the other non-early-returned branches return {}
. I think we discussed that already on a separate topic. We should probably make an issue.
Last updated: Jul 06 2025 at 12:14 UTC