# SynchronizedRef

A `SynchronizedRef<A>` is a [`Ref`](https://effect.plants.sh/state-management/ref/) whose updates can run
*effects* while computing the next value — and whose effectful updates are
serialized so they never overlap. Internally it guards updates with a semaphore:
while one effectful update runs, any other update to the same reference waits its
turn, then re-reads the now-current value.

Use it when the next value depends on an effect (a network call, a database
lookup, a [`Clock`](https://effect.plants.sh/scheduling/) read) and those updates must not race with one
another.

## The problem it solves

With a plain `Ref` you could read the value, run an effect, then write the result
back — but that is *three* separate operations. Between the read and the write,
another fiber can change the value, and your write silently overwrites theirs.
`SynchronizedRef.updateEffect` closes that gap: it holds the lock for the whole
read → effect → write cycle.

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

// Pretend this fetches the latest score for a user from a remote service.
const fetchDelta = (current: number): Effect.Effect<number> =>
  Effect.succeed(current + 10)

const program = Effect.gen(function*() {
  const score = yield* SynchronizedRef.make(0)

  // The update function returns an Effect. The whole read-run-write cycle is
  // serialized, so concurrent updates apply one after another instead of
  // racing on a stale value.
  const bump = SynchronizedRef.updateEffect(score, (n) => fetchDelta(n))

  // Run several effectful updates concurrently — they still compose correctly.
  yield* Effect.all([bump, bump, bump], { concurrency: "unbounded" })

  return yield* SynchronizedRef.get(score) // 30
})
```

If `score` were a plain `Ref` and we tried to express this as a `get`, then a
fetch, then a `set`, the three concurrent updates could each read `0` and write
`10`, losing two of the three increments. With `SynchronizedRef` the result is
always `30`.

## Same API as Ref, plus effectful variants

`SynchronizedRef` **extends `Ref`**, so every pure `Ref` operation works on it
unchanged — `get`, `set`, `update`, `modify`, and their `andGet` / `getAnd` /
`Some` variants — making it a drop-in replacement. The addition is the `Effect`
suffix family, where each updating operation has a companion `*Effect` variant
whose transform returns an `Effect` that is serialized under the lock:

- `updateEffect` — replace the value with the result of an effectful function.
- `updateAndGetEffect` / `getAndUpdateEffect` — the same, returning the new or
  previous value.
- `modifyEffect` — effectfully compute both a return value and the next stored
  value.
- `updateSomeEffect`, `modifySomeEffect`, ... — conditional effectful updates
  driven by an `Option`.

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

const program = Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(100)

  // modifyEffect returns a tuple [result, newValue]. The result is handed back
  // to the caller; the newValue is stored. Both are computed atomically under
  // the lock, even though the computation is effectful.
  const withdrawn = yield* SynchronizedRef.modifyEffect(ref, (balance) =>
    Effect.gen(function*() {
      const amount = balance >= 30 ? 30 : 0
      yield* Effect.log(`Withdrawing ${amount} from ${balance}`)
      return [amount, balance - amount] as const
    }))

  const remaining = yield* SynchronizedRef.get(ref)
  return { withdrawn, remaining } // { withdrawn: 30, remaining: 70 }
})
```
**The lock is held for the whole effect:** An effectful update function runs *while the semaphore is held*, so a slow
  effect inside `updateEffect` delays every other update to the same reference.
  Keep the work inside the update small and avoid blocking on unrelated effects.
  If the effect fails, the stored value is left unchanged.

## A serialized resource pool

A common use is coordinating access to a shared, effectfully-managed resource.
Here a service hands out connections from a pool, replenishing it with an effect
when it runs dry — and `SynchronizedRef` guarantees two fibers never grab the
same slot.

```ts
import { Context, Effect, Layer, SynchronizedRef } from "effect"

class ConnectionPool extends Context.Service<ConnectionPool, {
  // Borrow the next available connection id, opening more if needed.
  readonly acquire: Effect.Effect<number>
}>()("app/ConnectionPool") {
  static layer = Layer.effect(
    ConnectionPool,
    Effect.gen(function*() {
      // State: the ids currently free to hand out.
      const free = yield* SynchronizedRef.make<Array<number>>([])
      let nextId = 0

      const openConnection = Effect.sync(() => nextId++)

      const acquire = SynchronizedRef.modifyEffect(free, (available) =>
        available.length > 0
          // Fast path: reuse a free connection. No effect needed, but the whole
          // decision is still serialized so no two fibers take the same id.
          ? Effect.succeed([available[0], available.slice(1)] as const)
          // Slow path: open a new connection effectfully while holding the lock.
          : Effect.map(openConnection, (id) => [id, [] as Array<number>] as const))

      return ConnectionPool.of({ acquire })
    })
  )
}

const program = Effect.gen(function*() {
  const pool = yield* ConnectionPool
  // Even acquiring concurrently, each fiber receives a distinct id.
  const ids = yield* Effect.all(
    [pool.acquire, pool.acquire, pool.acquire],
    { concurrency: "unbounded" }
  )
  return ids // three distinct connection ids
}).pipe(Effect.provide(ConnectionPool.layer))
```

## When to prefer a plain Ref

If your update is a pure function of the current value, a plain
[`Ref`](https://effect.plants.sh/state-management/ref/) is already atomic and has no locking overhead —
use it. Reach for `SynchronizedRef` only when computing the next value requires an
effect that must stay serialized. And if you need the *whole group* of references
to update transactionally together, use [transactions (STM)](https://effect.plants.sh/transactions/).

## Reference

`SynchronizedRef` extends `Ref`, so the pure operations below behave exactly as
their `Ref` counterparts and inherit the same signatures — the only difference is
that an internal semaphore serializes every mutation. The distinguishing feature
is the `*Effect` family: a companion for each updating operation whose transform
returns an `Effect<...>`, run while the semaphore is held so effectful updates
never interleave.
**Effectful transforms hold the lock for their full duration:** Every `*Effect` operation runs its transform *while holding the lock*. Keep the
  effect short: a long-running effect inside, say, `updateEffect` blocks every
  other updater of the same reference until it completes. If the effect fails or
  is interrupted, the stored value is left unchanged. For atomic coordination
  across *multiple* references, use [transactions (STM)](https://effect.plants.sh/transactions/) instead.

### make

Creates a `SynchronizedRef` from an initial value, wrapped in an `Effect`. This is
the standard constructor inside an Effect program.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(0)
  return yield* SynchronizedRef.get(ref) // => 0
})
```

### makeUnsafe

Creates a `SynchronizedRef` synchronously, outside the `Effect` runtime. Reserve
for low-level or carefully controlled code.

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

const ref = SynchronizedRef.makeUnsafe(0)
SynchronizedRef.getUnsafe(ref) // => 0
```

### get

Reads the current value inside an `Effect`, without changing it.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make("ready")
  return yield* SynchronizedRef.get(ref) // => "ready"
})
```

### getUnsafe

Reads the current value synchronously, bypassing the `Effect` API and the
semaphore. For immediate access in low-level code.

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

const ref = SynchronizedRef.makeUnsafe(42)
SynchronizedRef.getUnsafe(ref) // => 42
```

### set

Replaces the value with a known value. Serialized with other synchronized
updates; returns `void`.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(0)
  yield* SynchronizedRef.set(ref, 10)
  return yield* SynchronizedRef.get(ref) // => 10
})
```

### getAndSet

Sets a new value and returns the *previous* value.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  return yield* SynchronizedRef.getAndSet(ref, 2) // => 1
})
```

### setAndGet

Sets a new value and returns the *new* value.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  return yield* SynchronizedRef.setAndGet(ref, 2) // => 2
})
```

### update

Applies a pure function to the current value and stores the result. Returns
`void`.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  yield* SynchronizedRef.update(ref, (n) => n + 1)
  return yield* SynchronizedRef.get(ref) // => 2
})
```

### updateAndGet

Applies a pure function and returns the *new* stored value.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  return yield* SynchronizedRef.updateAndGet(ref, (n) => n + 1) // => 2
})
```

### getAndUpdate

Applies a pure function and returns the *previous* stored value.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  return yield* SynchronizedRef.getAndUpdate(ref, (n) => n + 1) // => 1
})
```

### updateSome

Applies a partial update: `Option.some` stores the new value, `Option.none`
leaves the ref unchanged. Returns `void`.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  // Only increment while below 5.
  yield* SynchronizedRef.updateSome(ref, (n) =>
    n < 5 ? Option.some(n + 1) : Option.none())
  return yield* SynchronizedRef.get(ref) // => 2
})
```

### updateSomeAndGet

Like `updateSome`, but returns the resulting current value (the new value on
`some`, the unchanged value on `none`).

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(9)
  return yield* SynchronizedRef.updateSomeAndGet(ref, (n) =>
    n < 5 ? Option.some(n + 1) : Option.none()) // => 9 (left unchanged)
})
```

### getAndUpdateSome

Like `updateSome`, but returns the *previous* value whether or not the update
applied.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  return yield* SynchronizedRef.getAndUpdateSome(ref, (n) =>
    n < 5 ? Option.some(n + 1) : Option.none()) // => 1 (previous value)
})
```

### modify

Computes a `[result, newValue]` tuple from the current value, stores the new
value, and returns the result. The most general pure operation.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(100)
  // Withdraw 30: return the amount, store the remaining balance.
  return yield* SynchronizedRef.modify(ref, (balance) =>
    [30, balance - 30] as const) // => 30 (ref now holds 70)
})
```

### modifySome

Computes a `[result, Option<newValue>]` tuple. `Option.some` updates the ref;
`Option.none` leaves it unchanged. Returns the result.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(100)
  return yield* SynchronizedRef.modifySome(ref, (balance) =>
    balance >= 30
      ? ["ok", Option.some(balance - 30)] as const
      : ["insufficient", Option.none()] as const) // => "ok" (ref now holds 70)
})
```

### updateEffect

The defining operation: runs an effectful transform under the lock and stores its
successful result. Returns `void`. The transform may use any environment `R` and
fail with `E`.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(0)
  // The whole read -> effect -> write cycle is serialized.
  yield* SynchronizedRef.updateEffect(ref, (n) => Effect.succeed(n + 10))
  return yield* SynchronizedRef.get(ref) // => 10
})
```

### updateAndGetEffect

Like `updateEffect`, but returns the *new* stored value.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(0)
  return yield* SynchronizedRef.updateAndGetEffect(ref, (n) =>
    Effect.succeed(n + 10)) // => 10
})
```

### getAndUpdateEffect

Like `updateEffect`, but returns the *previous* stored value.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(0)
  return yield* SynchronizedRef.getAndUpdateEffect(ref, (n) =>
    Effect.succeed(n + 10)) // => 0 (previous value; ref now holds 10)
})
```

### updateSomeEffect

Effectful conditional update: the transform returns `Effect<Option<A>>`.
`Option.some` stores the new value; `Option.none` leaves the ref unchanged.
Returns `void`.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  yield* SynchronizedRef.updateSomeEffect(ref, (n) =>
    Effect.succeed(n < 5 ? Option.some(n + 1) : Option.none()))
  return yield* SynchronizedRef.get(ref) // => 2
})
```

### updateSomeAndGetEffect

Like `updateSomeEffect`, but returns the resulting current value (new value on
`some`, unchanged value on `none`).

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  return yield* SynchronizedRef.updateSomeAndGetEffect(ref, (n) =>
    Effect.succeed(n < 5 ? Option.some(n + 1) : Option.none())) // => 2
})
```

### getAndUpdateSomeEffect

Like `updateSomeEffect`, but returns the *previous* value whether or not the
update applied.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(1)
  return yield* SynchronizedRef.getAndUpdateSomeEffect(ref, (n) =>
    Effect.succeed(n < 5 ? Option.some(n + 1) : Option.none())) // => 1
})
```

### modifyEffect

The most general effectful operation: the transform returns
`Effect<[result, newValue]>`. The new value is stored and the result returned —
both computed atomically under the lock.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(100)
  // Effectfully decide the result and the next stored value together.
  return yield* SynchronizedRef.modifyEffect(ref, (balance) =>
    Effect.succeed([30, balance - 30] as const)) // => 30 (ref now holds 70)
})
```

### modifySomeEffect

Effectful `modifySome`: the transform returns
`Effect<[result, Option<newValue>]>`. `Option.some` stores the new value;
`Option.none` leaves it unchanged. Returns the result.

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

Effect.gen(function*() {
  const ref = yield* SynchronizedRef.make(100)
  return yield* SynchronizedRef.modifySomeEffect(ref, (balance) =>
    Effect.succeed(
      balance >= 30
        ? ["ok", Option.some(balance - 30)] as const
        : ["insufficient", Option.none()] as const
    )) // => "ok" (ref now holds 70)
})
```