In idiomatic C error handling usually means picking one application wide error enumeration a giant or throwing exceptions If a function only ever fails due to one specific error returning a large application wide error variant discards the precise bounds of what the function can actually do With the compiler derives an exact graded error pipeline Consider parsing validating and loading a user The resulting statically records that the pipeline yields a on success or fails with exactly one of or This exact union accumulates automatically via composition What Does Graded Mean Standard monads are rigid an requires every step in a pipeline to return the identical error type This forces you to define a monolithic global error union upfront A graded monad relaxes this restriction Each operation is indexed by a grade a set representing all its specific possible errors its effects by means of which is a disjoint set of types As you chain operations the compiler automatically adds these grades to the set The resulting error type is graded it expands or narrows during recovery to match the exact subset of errors possible in the compiled path providing strict static effect tracking subeffecting with zero boilerplate You may also use on a value side of most carriers except for which must be spelled Grading is opt in for chaining a on the error side enrols an in this union arithmetic while a plain holds every step to the identical error type A on the value side enrols an or into the same arithmetic on values TIP Mathematical note graded monads Formally a graded monad also known as an effect monad indexes a family of monadic carriers over a partially ordered monoid pomonoid of effects In that pomonoid is carried by the finite sets of C types Grades Finite sets of alternative types errors Monoidal multiplication Set union representing effect accumulation Identity The empty set representing the zero error never failing state Partial order Subset relation which licenses effect approximation subeffecting widening Taking union as the multiplication makes this monoid commutative and idempotent a join semilattice whose order is the one it induces Those are exactly the laws of Types as an algebra zero unit alternatives and products and they are why widening is coherent grades accumulated in any order through any intermediate supersets land on the same normalized set For a standard monad the binding operation maps In s graded monad bind accumulates effects across the pomonoid bind M_E langle A rangle to A to M_F langle B rangle to M_ E cup F langle B rangle Graded expected exact error sets identifies the lax monoidal functor this determines The same type precision extends to computations combined side by side rather than in sequence Conjunction evaluates independent computations and bundles them into a single carrier holding a of the successful values over a of the exact possible errors disjunction is its dual Sections 6 and 7 cover both The Two Cooperating Mechanisms Behind these precise compiled types are two independent mechanisms that cooperate to derive and eliminate these shapes Type algebra records and normalizes the exact stored C types using and as you compose operations The application protocol uses and ordinary C overload resolution to unpack those stored values and route them to your functions or lambdas To route multiple alternative paths inside the library provides which fuses unrelated lambdas into a single overload set These derived types are the explanation of the library s design not an internal template metaprogramming implementation detail std variant libfn auto parse_id std string_view > fn expected<UserId fn copack<NotANumber>> auto validate UserId > fn expected<UserId fn copack<OutOfRange>> auto load UserId > fn expected<User fn copack_for<IoError Missing>> auto graded_pipeline std string_view sv > void auto pipeline parse_id sv | fn and_then validate | fn and_then load The exact derived error union is recorded in the type static_assert std same_as<decltype pipeline fn expected<User fn copack_for<IoError Missing NotANumber OutOfRange>>> expected User NotANumber OutOfRange Missing IoError and_then expected<T E> E copack copack just<copack<Ts >> choice<Ts > copack expected expected<T E> E copack expected optional libfn copack libfn operator& pack copack operator| pack copack apply apply fn overload