I'm updating https://roc-lang.org/functional for the new compiler and I'm not sure how I should change this section. Now that we have completely hidden Task from the user, should we still talk about Tasks here? Note that Task is shown in bold below:
Asynchronous effects are commonly represented by a value such as a Promise or Future (Roc calls these Tasks), which represent an effect to be performed. Tasks can be composed together, potentially while customizing concurrency properties and supporting I/O interruptions like cancellation and timeouts.
Most languages also have a separate system for synchronous effects, namely side effects. Having two different ways to perform every I/O operation—one synchronous and one asynchronous—can lead to a lot of duplication across a language's ecosystem.
Instead of having side effects, Roc functions exclusively use managed effects in which they return descriptions of effects to run, in the form of Tasks. Tasks can be composed and chained together, until they are ultimately handed off (usually via a
mainfunction or something similar) to an effect runner outside the program, which actually performs the effects the tasks describe.Having only (potentially asynchronous) managed effects and no (synchronous) side effects both simplifies the language's ecosystem and makes certain guarantees possible. For example, the combination of managed effects and semantically immutable values means all Roc functions are pure—that is, they have no side effects and always return the same answer when called with the same arguments.
Pure functions {#pure-functions}
Pure functions have some valuable properties, such as referential transparency and being trivial to memoize. They also have testing benefits; for example, all Roc tests which either use simulated effects (or which do not involve Tasks at all) can never flake. They either consistently pass or consistently fail. Because of this, their results can be cached, so
roc testcan skip re-running them unless their source code (including dependencies) changed. (This caching has not yet been implemented, but is planned.)
I'm not sure, will have to think about this!
a relevant detail is that we don't have a fully working prototype of hosts that enable concurrency yet, beyond the proof-of-concept Brendan made awhile back
so although technically effects can be run "async without a keyword" (like Go does), it's kind of hard to talk through an explanation for that without having a concrete example host that supports it :sweat_smile:
there's no particular reason we couldn't have such a host right now, we just don't yet
Last updated: Apr 10 2026 at 12:38 UTC