Effect.ts: Absence as First-Class
State Management • Lesson 47 of 51
28. Ref Intro: Why We Need It
Regular variables in Effect don't work the way you expect - here's why
The Problem
// This creates subtle bugs!
let counter = 0;
const program = Effect.gen(function* () {
yield* Effect.sync(() => { counter++; });
yield* Effect.sync(() => { counter++; });
return counter;
});
await Effect.runPromise(program); // 2
await Effect.runPromise(program); // 4
Why This Breaks
Effects are descriptions that can be run multiple times. When you use regular variables:
- State leaks between runs
- The same program behaves differently each time
- It's impossible to reason about
The Solution: Ref
// This is safe and reusable!
const program = Effect.gen(function* () {
const counter = yield* Ref.make(0);
yield* Ref.update(counter, n => n + 1);
yield* Ref.update(counter, n => n + 1);
return yield* Ref.get(counter);
});
await Effect.runPromise(program); // 2
await Effect.runPromise(program); // 2
Key Insight
Ref makes state part of the Effect description.
- Regular variable: State lives "outside" the Effect (leaks)
- Ref: State lives "inside" the Effect (contained)
Each time you run a program with Ref.make(), you get fresh state. That's the whole point!
Understanding why Ref exists before learning how to use it
Part 47 of 51 in the Effect.ts Absence Modeling series