Pattern matches over the Exit.
onDie is optional and appended rather than inserted so existing three-argument
calls keep compiling. Omitting it routes a defect to onFailure — the pre-Die
behaviour, where defects were indistinguishable from typed failures. Supply it
when the distinction matters; note the value it receives is unknown, not E.
Returns the success value or throws
String representation
Exit represents the outcome of running an IO effect.
EchannelEDieexists so the error channel stops lying.IO.syncandIO.diedeclareE = never, so nothing they put in the error channel can be anE: a throwingIO.syncthunk, a throwingmap/flatMap/mapErrorcallback, andIO.dieall produce values the declared type says cannot exist. BeforeDiethese collapsed intoFailure, so a consumer that pattern-matched onerror._taggotundefinedwith no runtime signal that anything was wrong.Defects remain recoverable —
recover/recoverWith/fold/mapErrortreatDieexactly as they treatFailure. That is deliberate, and it is where functype parts company with ZIO: promoting defects to uncatchable would silently change what every existing.recover()catches.Dieis an observability fix, not a control-flow one — it records what the outcome really was when nothing recovered it.Note the sync interpreter cannot distinguish the two.
runSyncreturnsEither<E, A>, which has no third branch to put a defect in, and the sync interpreter signals failure by throwing the raw value — soFailandDiearrive identically.Dieis observable through the async terminals (runExit) and through theExithanded to abracketExitrelease.