Async Composable Architecture: Tasks

Episode #196 • Jul 11, 2022 • Subscriber-Only

This week we start fixing the problems we outlined last week. We build the tools necessary to start using concurrency tasks directly in reducers, and along the way we open Pandora’s box of existential types to solve some mind-bending type issues.

Testing async-received actions
Introducing TaskResult
An existential digression
A universal thought experiment
TaskResult equality and ergonomics
Next time: streams

Unlock This Episode

Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.


So, this is a pretty big missing part of the ergonomics story for the Composable Architecture. We need to figure out a way to use Effect.task in our reducers because there are a ton of benefits:

  • It makes for simpler dependency clients that can just use async instead of returning Effect values, which means that our dependencies don’t even need to depend on the Composable Architecture.
  • It makes for simpler live and mock instances of dependencies
  • It makes for simpler construction of effects in reducers, and we can chain multiple asynchronous tasks together by just awaiting one after another.
  • And finally it means we can even sometimes remove schedulers from our environment, especially if we don’t need to schedule time-based work.

But most importantly, we want to allow usage of Effect.task in our reducers in a way that does not affect tests. Testing is by far the most important feature of the Composable Architecture, and we try our hardest to never add a feature to the library that hurts testability. We should strive to be able to write fully deterministic tests that run immediately.

And Effect.task is really just the tip of the iceberg. There are a lot more ways we’d like to more deeply integrate the library with Swift’s concurrency tools, but let’s start with the problem of Effect.task not being usable in reducers.

The main problem with using async/await directly in the reducer is that all new asynchronous contexts are spun up when effects execute in tests, and we are forced to wait for small amounts of times for those tasks to finish and feed their data back into the system.

Let’s see how we can fix this.

This episode is for subscribers only.

Subscribe to Point-Free

Access this episode, plus all past and future episodes when you become a subscriber.

See plans and pricing

Already a subscriber? Log in


  1. Is Any a subtype or supertype of all types?

  2. Is All a subtype or supertype of all types?


Collection: Concurrency

Brandon Williams & Stephen Celis

Swift has many tools for concurrency, including threads, operation queues, dispatch queues, Combine and now first class tools built directly into the language. We start from the beginning to understand what the past tools excelled at and where they faultered in order to see why the new tools are so incredible.