In v3, Cause<E> was a recursive tree with six variants:
Empty | Fail<E> | Die | Interrupt | Sequential<E> | Parallel<E>
The Sequential and Parallel variants composed causes into a tree to
represent errors from finalizers or concurrent operations.
In v4, Cause<E> has been flattened to a simple wrapper around an array of
Reason values:
interface Cause<E> {
readonly reasons: ReadonlyArray<Reason<E>>
}
type Reason<E> = Fail<E> | Die | InterruptThere are only three reason variants — Fail, Die, and Interrupt. The
Empty, Sequential, and Parallel variants have been removed. An empty
cause is represented by an empty reasons array. Multiple failures (from
concurrent or sequential composition) are collected into a flat array.
v3 — pattern match on the recursive tree structure:
import { Cause } from "effect"
const handle = (cause: Cause.Cause<string>) => {
switch (cause._tag) {
case "Fail":
return cause.error
case "Die":
return cause.defect
case "Empty":
return undefined
case "Sequential":
return handle(cause.left)
case "Parallel":
return handle(cause.left)
case "Interrupt":
return cause.fiberId
}
}v4 — iterate over the flat reasons array:
import { Cause } from "effect"
const handle = (cause: Cause.Cause<string>) => {
for (const reason of cause.reasons) {
switch (reason._tag) {
case "Fail":
return reason.error
case "Die":
return reason.defect
case "Interrupt":
return reason.fiberId
}
}
}The v3 type-level guards (isFailType, isDieType, isInterruptType, etc.)
have been replaced by reason-level guards:
| v3 | v4 |
|---|---|
Cause.isEmptyType(cause) |
cause.reasons.length === 0 |
Cause.isFailType(cause) |
Cause.isFailReason(reason) |
Cause.isDieType(cause) |
Cause.isDieReason(reason) |
Cause.isInterruptType(cause) |
Cause.isInterruptReason(reason) |
Cause.isSequentialType(cause) |
Removed |
Cause.isParallelType(cause) |
Removed |
| v3 | v4 |
|---|---|
Cause.isFailure(cause) |
Cause.hasFails(cause) |
Cause.isDie(cause) |
Cause.hasDies(cause) |
Cause.isInterrupted(cause) |
Cause.hasInterrupts(cause) |
Cause.isInterruptedOnly(cause) |
Cause.hasInterruptsOnly(cause) |
| v3 | v4 |
|---|---|
Cause.empty |
Cause.empty |
Cause.fail(error) |
Cause.fail(error) |
Cause.die(defect) |
Cause.die(defect) |
Cause.interrupt(fiberId) |
Cause.interrupt(fiberId) |
Cause.sequential(left, right) |
Cause.combine(left, right) |
Cause.parallel(left, right) |
Cause.combine(left, right) |
In v4, Cause.combine concatenates the reasons arrays of two causes. The
distinction between sequential and parallel composition is no longer
represented in the data structure.
| v3 | v4 |
|---|---|
Cause.failureOption(cause) |
Cause.findErrorOption(cause) |
Cause.failureOrCause(cause) |
Cause.findError(cause) |
Cause.dieOption(cause) |
Cause.findDefect(cause) |
Cause.interruptOption(cause) |
Cause.findInterrupt(cause) |
Cause.failures(cause) |
cause.reasons.filter(Cause.isFailReason) |
Cause.defects(cause) |
cause.reasons.filter(Cause.isDieReason) |
Cause.interruptors(cause) |
Cause.interruptors(cause) |
Note: findError and findDefect return Result.Result instead of Option.
Use findErrorOption for the Option-based variant.
All *Exception classes have been renamed to *Error:
| v3 | v4 |
|---|---|
Cause.NoSuchElementException |
Cause.NoSuchElementError |
Cause.TimeoutException |
Cause.TimeoutError |
Cause.IllegalArgumentException |
Cause.IllegalArgumentError |
Cause.ExceededCapacityException |
Cause.ExceededCapacityError |
Cause.UnknownException |
Cause.UnknownError |
Cause.RuntimeException |
Removed |
Cause.InterruptedException |
Removed |
Cause.InvalidPubSubCapacityException |
Removed |
The corresponding guards follow the same pattern:
| v3 | v4 |
|---|---|
Cause.isNoSuchElementException(u) |
Cause.isNoSuchElementError(u) |
Cause.isTimeoutException(u) |
Cause.isTimeoutError(u) |
Cause.isIllegalArgumentException(u) |
Cause.isIllegalArgumentError(u) |
Cause.isExceededCapacityException(u) |
Cause.isExceededCapacityError(u) |
Cause.isUnknownException(u) |
Cause.isUnknownError(u) |
Cause.fromReasons(reasons)— construct aCausefrom an array ofReasonvalues.Cause.makeFailReason(error),Cause.makeDieReason(defect),Cause.makeInterruptReason(fiberId)— construct individualReasonvalues.Cause.annotate(cause, annotations)— attach annotations to aCause.Cause.findFail(cause),Cause.findDie(cause),Cause.findInterrupt(cause)— extract specific reason types using theResultmodule.Cause.filterInterruptors(cause)— extract interrupting fiber IDs as aResult.Cause.Done— a graceful completion signal for queues and streams.