# Ref

A `Ref<A>` is a fiber-safe mutable cell holding a single value of type `A`. It is
the workhorse of Effect state management: a controlled, atomic alternative to a
plain mutable variable. Reads, writes, and transformations are all effects, so
they sequence with the rest of your program and stay correct when several fibers
touch the same `Ref` concurrently.

Reach for a `Ref` whenever the next value is a *pure* function of the current one
— a counter, an accumulator, a small piece of in-memory configuration.

## Creating and updating a Ref

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

const program = Effect.gen(function*() {
  // `make` returns an effect, because allocating shared state is itself an
  // effect — it must happen at a well-defined point in the program.
  const counter = yield* Ref.make(0)

  // `update` reads, transforms, and writes back in one atomic step. Prefer it
  // over a separate `get` + `set` whenever the new value depends on the old.
  yield* Ref.update(counter, (n) => n + 1)

  // `get` reads the current value without changing it.
  return yield* Ref.get(counter) // 1
})
```
**Every Ref operation is an effect:** Reading from or writing to a `Ref` always produces an effect — even
  construction with `Ref.make`. This is what makes the reference fiber-safe and
  lets it compose with the rest of your program.

## The core operations

A handful of operations cover almost everything:

- `Ref.get` / `Ref.set` — read the value, or replace it with a known value.
- `Ref.update` — replace the value with `f(current)`, atomically. Use this
  whenever the new value depends on the old one.
- `Ref.modify` — atomically compute *two* things from the current value: a
  return value and the next stored value.

`modify` is the most general operation. It takes a function returning a
`[result, newValue]` tuple, stores `newValue`, and hands you back `result`. This
lets you read-and-update in a single atomic step — useful for things like handing
out unique IDs:

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

const program = Effect.gen(function*() {
  const nextId = yield* Ref.make(1)

  // Atomically take the current id and advance the counter. No two fibers can
  // ever observe the same id, even calling this concurrently.
  const allocate = Ref.modify(nextId, (id) => [id, id + 1] as const)

  const a = yield* allocate // 1
  const b = yield* allocate // 2
  return [a, b]
})
```

Each operation also comes in `andGet` / `getAnd` variants when you want the new or
previous value back: `updateAndGet`, `getAndUpdate`, `getAndSet`, `setAndGet`.
The `Some` variants (`updateSome`, `modifySome`, `getAndUpdateSome`) take a
function returning an `Option` and leave the value untouched when it returns
`Option.none()`, which is handy for conditional state transitions.

## Sharing a Ref through a service

A `Ref` is rarely passed around by hand. Instead, wrap it in a
[service](https://effect.plants.sh/services-and-layers/) so any subprogram can reach the same shared
state. This is the idiomatic v4 way to expose mutable state, and it keeps the
operations you allow on the state in one place.

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

// A small counter service. The Ref stays private inside the layer; consumers
// only see the operations we choose to expose.
class Counter extends Context.Service<Counter, {
  readonly increment: Effect.Effect<void>
  readonly decrement: Effect.Effect<void>
  readonly current: Effect.Effect<number>
}>()("app/Counter") {
  // The layer allocates the Ref once, when the service is constructed.
  static layer = Layer.effect(
    Counter,
    Effect.gen(function*() {
      const ref = yield* Ref.make(0)
      return Counter.of({
        increment: Ref.update(ref, (n) => n + 1),
        decrement: Ref.update(ref, (n) => n - 1),
        current: Ref.get(ref)
      })
    })
  )
}

const program = Effect.gen(function*() {
  const counter = yield* Counter
  yield* counter.increment
  yield* counter.increment
  yield* counter.decrement
  return yield* counter.current // 1
})

// Every fiber that runs with this layer shares the same underlying Ref.
const runnable = program.pipe(Effect.provide(Counter.layer))
```

Because the service exposes only `increment`, `decrement`, and `current`, callers
cannot set the counter to an arbitrary value — the `Ref` is an implementation
detail.

## Using a Ref across fibers

A `Ref` shines when several fibers update the same state at once. Each individual
`update` is atomic, so concurrent increments cannot clobber one another.

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

const program = Effect.gen(function*() {
  const ref = yield* Ref.make(0)

  // Fork two fibers that each increment the shared counter many times.
  const work = Effect.forEach(
    Array.from({ length: 100 }, (_, i) => i),
    () => Ref.update(ref, (n) => n + 1),
    { discard: true }
  )

  const fiber1 = yield* Effect.forkChild(work)
  const fiber2 = yield* Effect.forkChild(work)

  // Wait for both to finish before reading the final total.
  yield* Fiber.join(fiber1)
  yield* Fiber.join(fiber2)

  return yield* Ref.get(ref) // 200 — no updates were lost
})
```

The result is always `200`: because `update` is atomic, the two fibers'
increments are correctly interleaved rather than racing on a read-modify-write.
**Atomic per operation, not per group:** Each `Ref` operation is atomic on its own, but a `get` followed by a separate
  `set` is *two* operations — another fiber may change the value in between.
  Whenever the new value depends on the current one, express it as a single
  `update` or `modify`. And when multiple references must change together as one
  consistent unit, use [transactions (STM)](https://effect.plants.sh/transactions/) instead.

## When a Ref is not enough

A plain `Ref` cannot run an effect to compute its next value while staying
serialized — its update functions must be pure. If your update needs to perform
an effect (call an API, read the [`Clock`](https://effect.plants.sh/scheduling/)) and must not interleave
with other updates, use [`SynchronizedRef`](https://effect.plants.sh/state-management/synchronized-ref/).
If other parts of the program need to *observe* every change as a stream, use
[`SubscriptionRef`](https://effect.plants.sh/state-management/subscription-ref/).

## Reference

This section enumerates every public export of the `Ref` module. Most update
operations are **dual**: they have both a data-first form `Ref.update(ref, f)`
and a data-last / pipeable form `ref.pipe(Ref.update(f))`. The examples below use
the data-first form; either works.
**Ref vs SynchronizedRef vs transactions:** A `Ref`'s update functions are **pure** — `(a: A) => A` (or `=> Option<A>`,
  `=> [B, A]`). If a transition must run an effect while staying serialized, use
  [`SynchronizedRef`](https://effect.plants.sh/state-management/synchronized-ref/), whose update functions
  return effects. When several references must change together as a single atomic
  unit, reach for [transactions (STM)](https://effect.plants.sh/transactions/) and the `Tx*` data
  structures instead — a single `Ref` is only atomic with respect to itself.

### Constructors

#### make

Creates a `Ref<A>` with an initial value. Returns an `Effect<Ref<A>>` because
allocating shared state must happen at a defined point in the program.

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

const program = Effect.gen(function*() {
  const ref = yield* Ref.make(42)
  return yield* Ref.get(ref) // => 42
})
```

#### makeUnsafe

Allocates a `Ref<A>` synchronously, returning the `Ref<A>` directly (not an
effect). An escape hatch for constructing state outside of Effect; prefer
`Ref.make` inside Effect programs.

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

const counter = Ref.makeUnsafe(0)
const value = Ref.getUnsafe(counter)
console.log(value) // => 0
```

### Reading

#### get

Reads the current value of the `Ref` as an effect, without changing it.

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

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

#### getUnsafe

Reads the current value synchronously, returning `A` directly. An escape hatch
for peeking at state outside Effect; prefer `Ref.get` in Effect programs.

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

const ref = Ref.makeUnsafe(42)
const value = Ref.getUnsafe(ref)
console.log(value) // => 42
```

### Setting

#### set

Replaces the current value with a known value. Returns `Effect<void>`.

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

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

#### getAndSet

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

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

const program = Effect.gen(function*() {
  const ref = yield* Ref.make("initial")
  const previous = yield* Ref.getAndSet(ref, "updated")
  console.log(previous) // => "initial"
  return yield* Ref.get(ref) // => "updated"
})
```

#### setAndGet

Sets a new value and returns that **new** value, atomically.

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

const program = Effect.gen(function*() {
  const ref = yield* Ref.make(10)
  const next = yield* Ref.setAndGet(ref, 42)
  console.log(next) // => 42
})
```

### Updating with a pure function

#### update

Replaces the value with `f(current)`, atomically. Returns `Effect<void>`. The
go-to operation whenever the new value depends on the old.

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

const program = Effect.gen(function*() {
  const counter = yield* Ref.make(5)
  yield* Ref.update(counter, (n) => n * 2)
  return yield* Ref.get(counter) // => 10
})
```

#### updateAndGet

Applies `f` to the current value and returns the resulting **new** value.

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

const program = Effect.gen(function*() {
  const counter = yield* Ref.make(5)
  const next = yield* Ref.updateAndGet(counter, (n) => n * 3)
  console.log(next) // => 15
})
```

#### getAndUpdate

Applies `f` to the current value, stores `f(old)`, and returns the **old** value.

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

const program = Effect.gen(function*() {
  const counter = yield* Ref.make(10)
  const previous = yield* Ref.getAndUpdate(counter, (n) => n * 2)
  console.log(previous) // => 10
  return yield* Ref.get(counter) // => 20
})
```

### Conditional / partial updates

Each of these takes a function returning `Option<A>`. When it returns
`Option.none()`, the `Ref` is left unchanged.

#### updateSome

Applies a partial update: stores the value inside `Option.some`, or leaves the
`Ref` unchanged on `Option.none()`. Returns `Effect<void>`.

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

const program = Effect.gen(function*() {
  const counter = yield* Ref.make(5)

  // 5 is odd → Option.none() → unchanged
  yield* Ref.updateSome(counter, (n) =>
    n % 2 === 0 ? Option.some(n * 2) : Option.none())
  console.log(yield* Ref.get(counter)) // => 5

  yield* Ref.set(counter, 6)
  // 6 is even → Option.some(12) → updated
  yield* Ref.updateSome(counter, (n) =>
    n % 2 === 0 ? Option.some(n * 2) : Option.none())
  console.log(yield* Ref.get(counter)) // => 12
})
```

#### updateSomeAndGet

Like `updateSome`, but returns the **current** value after the potential update
(the new value if updated, otherwise the unchanged value).

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

const program = Effect.gen(function*() {
  const counter = yield* Ref.make(10)

  const r1 = yield* Ref.updateSomeAndGet(counter, (n) =>
    n > 5 ? Option.some(n / 2) : Option.none())
  console.log(r1) // => 5 (updated)

  const r2 = yield* Ref.updateSomeAndGet(counter, (n) =>
    n > 5 ? Option.some(n / 2) : Option.none())
  console.log(r2) // => 5 (5 is not > 5, unchanged)
})
```

#### getAndUpdateSome

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

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

const program = Effect.gen(function*() {
  const counter = yield* Ref.make(5)

  const previous = yield* Ref.getAndUpdateSome(counter, (n) =>
    n > 3 ? Option.some(n * 2) : Option.none())
  console.log(previous) // => 5 (old value)
  return yield* Ref.get(counter) // => 10 (updated)
})
```

### Read-and-modify

#### modify

The most general operation. `f` receives the current value and returns a
`[result, newValue]` tuple: the `Ref` is set to `newValue` and the effect returns
`result`.

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

const program = Effect.gen(function*() {
  const counter = yield* Ref.make(10)

  // f: (n) => [result, newValue]
  const result = yield* Ref.modify(counter, (n) => [`was ${n}`, n * 2])
  console.log(result) // => "was 10"
  return yield* Ref.get(counter) // => 20
})
```

#### modifySome

The partial variant of `modify`. `f` returns `[result, Option<A>]`: the `Ref` is
updated when the option is `Option.some`, left unchanged on `Option.none()`, and
the effect always returns `result`.

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

const program = Effect.gen(function*() {
  const counter = yield* Ref.make(5)

  // f: (n) => [result, Option<newValue>]
  const r1 = yield* Ref.modifySome(counter, (n) =>
    n > 3
      ? [`incremented ${n}`, Option.some(n + 10)]
      : ["no change", Option.none()])
  console.log(r1) // => "incremented 5"
  console.log(yield* Ref.get(counter)) // => 15

  const r2 = yield* Ref.modifySome(counter, (n) =>
    n < 10
      ? [`decremented ${n}`, Option.some(n - 5)]
      : ["no change", Option.none()])
  console.log(r2) // => "no change"
  console.log(yield* Ref.get(counter)) // => 15 (unchanged)
})
```

### Types

#### Ref

The model interface: `Ref<A>` is an invariant, pipeable handle to a single value
of type `A`. You rarely write the type by hand — it is produced by `make` /
`makeUnsafe` and threaded through the operations above.

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

// Annotating a service field, for example:
interface State {
  readonly count: Ref.Ref<number>
}

const make: Effect.Effect<State> = Effect.gen(function*() {
  const count = yield* Ref.make(0)
  return { count }
})
```