# Using Generators

`Effect.gen` lets you write effectful code in a familiar, imperative style -
the same shape as `async`/`await`, but for effects. You pass it a generator
function, and inside it you use `yield*` to run an effect and bind its success
value to a variable. Errors and service requirements are threaded through the
types for you, so the result is a single `Effect` describing the whole sequence.

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

// Use Schema.TaggedErrorClass to define a typed, tagged error.
class FileProcessingError extends Schema.TaggedErrorClass<FileProcessingError>()(
  "FileProcessingError",
  { message: Schema.String }
) {}

const program = Effect.gen(function*() {
  yield* Effect.log("Starting the file processing...")
  yield* Effect.log("Reading file...")

  // Raising an error short-circuits the generator. Always `return` the
  // yielded error so TypeScript knows execution stops here and narrows the
  // types of anything after it.
  return yield* new FileProcessingError({ message: "Failed to read the file" })
}).pipe(
  // Attach additional behaviour with `.pipe` after the generator.
  Effect.catch((error) => Effect.logError(`An error occurred: ${error}`)),
  Effect.withSpan("fileProcessing")
)

Effect.runFork(program)
```

## How `yield*` works

`yield*` is the heart of the syntax. Yielding an `Effect<A, E, R>`:

- **runs** that effect at this point in the sequence,
- **binds** its success value `A` to the left-hand side,
- and **accumulates** its error type `E` and requirements `R` into the overall
  effect that `Effect.gen` returns.

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

const divide = (a: number, b: number) =>
  b === 0
    ? Effect.fail("Cannot divide by zero" as const)
    : Effect.succeed(a / b)

//      ┌─── Effect<number, "Cannot divide by zero">
//      ▼
const program = Effect.gen(function*() {
  // Each yield* gives back the success value of the effect.
  const a = yield* Effect.succeed(10)
  const b = yield* Effect.succeed(2)

  // If `divide` fails, the generator stops and the error becomes the
  // failure of the whole program - the next line never runs.
  const result = yield* divide(a, b)

  yield* Effect.log(`10 / 2 = ${result}`)
  return result
})
```

Because `yield*` returns the plain success value, you can use ordinary
JavaScript in between: `const`/`let`, arithmetic, `if`, early `return`. You do
**not** need any special operators for non-effectful code.

## Short-circuiting on failure

A generator runs top to bottom until something fails. The first failure stops
execution and becomes the failure of the entire effect - just like `throw`
unwinds an `async` function, but tracked in the type system.

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

const program = Effect.gen(function*() {
  yield* Effect.log("step 1")
  yield* Effect.fail("boom" as const) // execution stops here
  yield* Effect.log("step 2") // never runs
})
```

Always `return yield*` when yielding an effect that you intend as the failure
path (like a constructed error). The `return` tells TypeScript control will not
continue, which keeps later code correctly typed.

## Yieldable values beyond Effect

Some data types are also yieldable inside a generator. For example, an
[`Option`](https://effect.plants.sh/data-types/) yields its inner value when it is `Some`, and
short-circuits with a `NoSuchElementError` when it is `None`:

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

const lookup = (key: string): Option.Option<number> =>
  key === "answer" ? Option.some(42) : Option.none()

const program = Effect.gen(function*() {
  // Yielding a `Some` produces its value...
  const x = yield* lookup("answer")
  // ...while a `None` fails the effect with NoSuchElementError.
  const y = yield* lookup("missing")
  return x + y
})
```

## Using `this` inside a generator

If you need access to the surrounding object (for example inside a class
method), pass `{ self: this }` as the first argument and the generator receives
it as `this`:

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

class Calculator {
  base = 100

  total = Effect.gen({ self: this }, function*() {
    // `this` refers to the Calculator instance.
    const extra = yield* Effect.succeed(23)
    return this.base + extra
  })
}
```

## When to reach for `gen`

Use `Effect.gen` whenever a computation has multiple sequential steps, local
variables, or branching - it is the most readable way to express that. For a
function that *returns* an effect, prefer
[`Effect.fn`](https://effect.plants.sh/essentials/effect-fn/) over a plain function that returns
`Effect.gen(...)`. For short transformations and attaching cross-cutting
behaviour, [pipelines](https://effect.plants.sh/essentials/building-pipelines/) are often cleaner.