# Deferred

A `Deferred<A, E>` is a write-once, promise-like cell. It starts empty, can be
**completed exactly once** (with a success value, a typed failure, a defect, or
interruption), and any number of fibers can `await` it. Awaiters suspend without
blocking until a producer completes the cell, and then they all resume with the
same result. Every completion attempt after the first is a no-op that returns
`false`, so only the fiber that wins the race actually sets the value.

Reach for a `Deferred` whenever one fiber must hand a single result, failure, or
"go" signal to one or more other fibers: a one-shot handoff, a one-to-many
broadcast, or a readiness signal.

## One fiber computes, others await

Here a producer fiber computes a value and completes the `Deferred`, while
several forked consumers await it. All consumers suspend until the single
`succeed` lands, then resume with the same value.

```ts
import { Deferred, Effect, Fiber } from "effect"

const program = Effect.gen(function*() {
  const result = yield* Deferred.make<number>()

  // Three consumers, each forked, all blocked on the same cell
  const consumers = yield* Effect.forEach(
    [1, 2, 3],
    (id) =>
      Effect.forkChild(
        Effect.gen(function*() {
          const value = yield* Deferred.await(result)
          yield* Effect.log(`consumer ${id} got ${value}`)
          return value
        })
      ),
    { concurrency: "unbounded" }
  )

  // The producer computes once, then broadcasts to every awaiter
  yield* Effect.sleep("50 millis")
  yield* Deferred.succeed(result, 42)

  return yield* Fiber.joinAll(consumers)
})

// => [42, 42, 42], with all three consumers logging "got 42"
```

The completion is stable: a consumer that awaits *after* the cell is already
completed resumes immediately with the stored result rather than blocking.

## Readiness signal

A `Deferred<void>` carrying no meaningful value is a clean way to say "the
system is ready, you may proceed." A background fiber opens the gate, and other
fibers wait on it before continuing. This is the pattern used to make a
`SubscriptionRef` stream start before a writer publishes — see
[SubscriptionRef](https://effect.plants.sh/state-management/subscription-ref/).

```ts
import { Deferred, Effect, Fiber } from "effect"

const program = Effect.gen(function*() {
  const ready = yield* Deferred.make<void>()

  const worker = yield* Effect.forkChild(
    Effect.gen(function*() {
      yield* Deferred.await(ready) // suspends until the gate opens
      return "started after ready"
    })
  )

  // Do setup work, then open the gate exactly once
  yield* Effect.sleep("20 millis")
  yield* Deferred.succeed(ready, undefined)

  return yield* Fiber.join(worker)
})

// => "started after ready"
```

## Producer / consumer handoff

A `Deferred<A, E>` can carry a failure as well as a value. The consumer's
`await` re-raises whatever the producer used to complete the cell, so a failed
handoff fails the awaiting fiber.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const handoff = yield* Deferred.make<string, Error>()

  yield* Effect.forkChild(
    Effect.gen(function*() {
      yield* Effect.sleep("10 millis")
      yield* Deferred.fail(handoff, new Error("upstream unavailable"))
    })
  )

  // The error propagates here when we await
  return yield* Deferred.await(handoff).pipe(
    Effect.catch((error) => Effect.succeed(`recovered: ${error.message}`))
  )
})

// => "recovered: upstream unavailable"
```

## Deferred vs Latch

A [`Latch`](https://effect.plants.sh/concurrency/semaphore-and-latch/) and a `Deferred` are both
fiber-safe coordination primitives, but they solve different problems:

- A **`Latch`** is a *reusable* open/close gate that carries **no value**. You
  can `close` it again after opening, making it a pause/resume switch for a
  stream or a worker pool.
- A **`Deferred`** is *one-shot* and **carries the value or failure**. It can be
  completed exactly once and never reset; later completion attempts return
  `false`.

Use a `Latch` to gate execution repeatedly; use a `Deferred` for a single handoff
of a result. For many values over time, use a
[`Queue` or `PubSub`](https://effect.plants.sh/concurrency/queue-and-pubsub/) instead.

## Reference

### make

Allocates a new empty `Deferred` inside an `Effect` workflow.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number, string>()
  yield* Deferred.succeed(deferred, 42)
  return yield* Deferred.await(deferred)
})
// => 42
```

### makeUnsafe

Allocates an empty `Deferred` synchronously, outside the `Effect` runtime. Use
only in low-level integration code.

```ts
import { Deferred } from "effect"

const deferred = Deferred.makeUnsafe<number>()
// => an empty Deferred<number>
```

### await

Suspends the current fiber until the `Deferred` is completed, then resumes with
its stored success, failure, defect, or interruption. Returns immediately if the
cell is already completed.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  yield* Deferred.succeed(deferred, 42)
  return yield* Deferred.await(deferred)
})
// => 42
```

### poll

Inspects completion without suspending. Returns `Option.none()` while pending and
`Option.some(effect)` once completed, where `effect` is the stored completion
effect you can run to observe the result.

```ts
import { Deferred, Effect, Option } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()

  const before = yield* Deferred.poll(deferred)
  console.log(Option.isNone(before)) // => true

  yield* Deferred.succeed(deferred, 42)

  const after = yield* Deferred.poll(deferred)
  // after is Option.some(Effect.succeed(42))
  return yield* Option.getOrThrow(after) // run the stored effect
})
// => 42
```

### isDone

Returns `true` if the `Deferred` has already been completed (with a value, error,
defect, or interruption), `false` otherwise.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  const before = yield* Deferred.isDone(deferred) // => false
  yield* Deferred.succeed(deferred, 42)
  const after = yield* Deferred.isDone(deferred) // => true
  return [before, after]
})
// => [false, true]
```

### isDoneUnsafe

Synchronous, non-`Effect` version of `isDone`. Returns a plain boolean for
low-level code that cannot return an `Effect`.

```ts
import { Deferred } from "effect"

const deferred = Deferred.makeUnsafe<number>()
console.log(Deferred.isDoneUnsafe(deferred)) // => false
```

### succeed

Attempts to complete the `Deferred` with a success value. Returns `true` if this
call won the race and completed it, `false` if it was already completed.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  const won = yield* Deferred.succeed(deferred, 42) // => true
  const again = yield* Deferred.succeed(deferred, 99) // => false (no-op)
  return [won, again, yield* Deferred.await(deferred)]
})
// => [true, false, 42]
```

### sync

Like `succeed`, but the value is computed lazily when the completion effect
runs. Returns a boolean indicating whether this call completed the cell.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  yield* Deferred.sync(deferred, () => 42) // => true
  return yield* Deferred.await(deferred)
})
// => 42
```

### fail

Attempts to complete the `Deferred` with a typed failure. Awaiters fail with that
error. Returns `true` if this call completed the cell.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number, string>()
  const won = yield* Deferred.fail(deferred, "boom") // => true
  return yield* Deferred.await(deferred).pipe(Effect.flip)
})
// => "boom"
```

### failSync

Like `fail`, but the error is computed lazily when the completion effect runs.
Returns a boolean indicating whether this call completed the cell.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number, string>()
  const won = yield* Deferred.failSync(deferred, () => "lazy boom") // => true
  return won
})
// => true
```

### failCause

Attempts to complete the `Deferred` with a full `Cause`,
letting you carry composite failures (e.g. interruption plus an error). Returns a
boolean indicating whether this call completed the cell.

```ts
import { Cause, Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number, string>()
  const won = yield* Deferred.failCause(deferred, Cause.fail("boom")) // => true
  return won
})
// => true
```

### failCauseSync

Like `failCause`, but the `Cause` is computed lazily when the completion effect
runs. Returns a boolean indicating whether this call completed the cell.

```ts
import { Cause, Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number, string>()
  const won = yield* Deferred.failCauseSync(deferred, () => Cause.fail("lazy")) // => true
  return won
})
// => true
```

### die

Attempts to complete the `Deferred` with an unexpected defect. Awaiters die with
that defect. Returns a boolean indicating whether this call completed the cell.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  const won = yield* Deferred.die(deferred, new Error("bug")) // => true
  return won
})
// => true
```

### dieSync

Like `die`, but the defect is computed lazily when the completion effect runs.
Returns a boolean indicating whether this call completed the cell.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  const won = yield* Deferred.dieSync(deferred, () => new Error("lazy bug")) // => true
  return won
})
// => true
```

### done

Completes the `Deferred` with an already computed [`Exit`](https://effect.plants.sh/error-management/result-and-exit/),
covering both the success and failure case in one call. Returns a boolean
indicating whether this call completed the cell.

```ts
import { Deferred, Effect, Exit } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  const won = yield* Deferred.done(deferred, Exit.succeed(42)) // => true
  return yield* Deferred.await(deferred)
})
// => 42
```

### doneUnsafe

Synchronous, non-`Effect` version of `done` that completes the `Deferred` with a
completion `Effect` directly. Reserved for low-level code. Returns a plain
boolean.

```ts
import { Deferred, Effect } from "effect"

const deferred = Deferred.makeUnsafe<number>()
const won = Deferred.doneUnsafe(deferred, Effect.succeed(42)) // => true
```

### complete

Runs the supplied effect once, memoizes its result as an `Exit`, and completes
the `Deferred` with that result. Every awaiter observes the same memoized
outcome. Returns a boolean indicating whether this call completed the cell.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  const won = yield* Deferred.complete(deferred, Effect.succeed(42)) // => true
  return yield* Deferred.await(deferred)
})
// => 42
```

### completeWith

Stores the supplied effect directly as the completion, **without** running or
memoizing it. Each awaiter runs the stored effect independently. Returns a
boolean indicating whether this call completed the cell.

```ts
import { Deferred, Effect, Ref } from "effect"

const program = Effect.gen(function*() {
  const counter = yield* Ref.make(0)
  const deferred = yield* Deferred.make<number>()

  // The increment effect is stored, not run yet
  yield* Deferred.completeWith(
    deferred,
    Ref.updateAndGet(counter, (n) => n + 1)
  )

  const a = yield* Deferred.await(deferred) // runs the effect => 1
  const b = yield* Deferred.await(deferred) // runs it AGAIN => 2
  return [a, b]
})
// => [1, 2]  (each await re-ran the stored effect)
```
**complete vs completeWith:** `complete` runs the effect a single time and shares its **memoized result** with
every awaiter, so all waiters observe the same value. `completeWith` stores the
**effect itself**; each awaiter executes it independently, so effects with side
effects (like the `Ref` increment above) run once per `await`. Prefer `complete`
unless you specifically want per-waiter re-execution.

### into

Data-last combinator over an effect: runs the effect and uses its `Exit`
(success, failure, defect, or interruption) to attempt completion of the given
`Deferred`. The returned effect cannot fail and succeeds with a boolean.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number, string>()

  // Pipe an effect's result into the Deferred
  const won = yield* Effect.succeed(42).pipe(Deferred.into(deferred)) // => true

  return yield* Deferred.await(deferred)
})
// => 42
```

### interrupt

Attempts to complete the `Deferred` as interrupted by the **current** fiber.
Awaiters are interrupted. Returns a boolean indicating whether this call
completed the cell.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  const won = yield* Deferred.interrupt(deferred) // => true
  return won
})
// => true
```

### interruptWith

Like `interrupt`, but completes as interrupted by a **specific** fiber id.
Returns a boolean indicating whether this call completed the cell.

```ts
import { Deferred, Effect } from "effect"

const program = Effect.gen(function*() {
  const deferred = yield* Deferred.make<number>()
  const won = yield* Deferred.interruptWith(deferred, 42) // => true
  return won
})
// => true
```
**Interrupting a waiter is not completing the Deferred:** Interrupting a fiber that is currently blocked on `Deferred.await` simply removes
that fiber from the waiter list. It does **not** complete the `Deferred` — other
awaiters keep waiting, and the cell can still be completed later.

### isDeferred

Type guard that checks whether an unknown value is a `Deferred`. Useful at
runtime boundaries.

```ts
import { Deferred } from "effect"

const deferred = Deferred.makeUnsafe<number>()
console.log(Deferred.isDeferred(deferred)) // => true
console.log(Deferred.isDeferred({})) // => false
```