Disjunction evaluates alternative computations keeping the first successful result fails only if both operands fail dual to conjunction their values union into a and their errors combine into a If both operands share the same value type the value side remains ungraded A operand enters the sum as If either error side is graded the product distributes over it the full Cartesian product when both are graded yielding a canonical of s The runtime semantics are exact The result type records every combination of failures at runtime the leftmost operand holding a value wins Both operands are fully constructed before runs because C evaluates operands eagerly This is a value selection rule not a lazy fallback Disjunction over carriers only Unlike conjunction disjunction has no data level form Neither nor the n ary fold accepts a a or a scalar Therefore built in operations such as bitwise on integers are never confused with disjunction Disjunction with the Identity Cluster When an operand belongs to the identity cluster The identity cluster the disjunction cannot fail Error Annihilation The error side gains an uninhabited factor which annihilates the error product and collapses the channel Infallible Folding The result folds into a non failing carrier if there is a single successful type or if the sum is heterogeneous TIP Mathematical note annihilation and totality Disjunction is the categorical dual of conjunction values add along where conjunction multiplies along and errors multiply where conjunction unions Both structures are strict in the sense Product composition with operator& conjunction describes What does not dualize is the role of the uninhabited and that is what makes an identity operand behave so differently on the two sides Under conjunction it is the unit of the error union so an identity operand leaves the error channel as it found it Under disjunction it is the annihilator of the error product so a single identity operand empties the channel outright The resulting error side is uninhabited by construction not merely empty at runtime but incapable of holding a value which is what renders the whole disjunction total and folds it into the identity cluster a | b copack pack void pack<> copack pack auto operator_or_composition fn expected<int Error> a fn expected<bool OtherError> b > void auto result a | b static_assert std same_as<decltype result fn expected<fn copack_for<int bool> fn pack<Error OtherError>>> operator| operator| fn disjoin pack copack OR copack<> just<T> choice<Ts > auto test_disjoin fn expected<int Error> a fn expected<bool OtherError> b > void Multiple fallible operands compose cleanly auto res1 fn disjoin a b static_assert std same_as<decltype res1 fn expected<fn copack_for<int bool> fn pack<Error OtherError>>> Because just<double> cannot fail the entire disjunction with infallible operands becomes total auto res2 fn disjoin a b fn just<double> 1 5 static_assert std same_as<decltype res2 fn choice<bool double int>> copack<>