You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Allow lvalue-reference alternatives in copack #448
copack refuses reference alternatives. This blocks sums of borrowed values: in PR #437, just<int&> | just<long&> can only copy into choice<int, long>, and an and_then over a choice whose branches return different reference just types is refused, because no copack can hold the reference results. This issue proposes admitting lvalue-reference alternatives, held as pointers, the way just<T&> and optional<T&> hold their referents.
Why this is a sum, unlike a reference to a copack
copack<A&, B&> is the sum of locations L(A)+L(B). Each A& has an injection into it, so the type is closed under the operations that form sums (|, the superset join). A reference to a copack, copack<A, B>&, has no such injections, which is why #434 remains open. Admitting reference alternatives also gives #434's snapshot distribution, L(A+B) → L(A)+L(B), a concrete target type: a borrowed copack can be distributed into a copack of references.
Proposed semantics
An alternative T& is stored as a pointer to T. Rvalue-reference alternatives remain refused, as in pack, optional and just.
Copy assignment rebinds; it never assigns through the reference.
Callables receive T& for a T& alternative, regardless of the copack's value category or constness, as with just<T&>. The tuple protocol for singular copacks (Add tuple protocol support for singular copacks #435) yields the same reference.
Comparisons compare referents, as just<T&> and optional<T&> do.
T, T& and T const& are distinct alternatives. copack_for does not merge them, so the distinction between owning, mutable and read-only access is preserved.
Owning and reference alternatives can be mixed in one copack.
A reference to a pack or a copack is not admitted as an alternative (copack<pack<A, B>&>), as just<T&> and optional<T&> refuse such referents: how a reference to a product or a sum takes part in conjunction, disjunction and grading is an open question.
Construction
A value selects its alternative as overload resolution would select among functions taking each alternative type. Given int x:
copack<int&>{x} binds the reference.
copack<int, int&>{x} is ambiguous and is rejected, as foo(x) is ambiguous for overloads foo(int) and foo(int&). Select the alternative explicitly with std::in_place_type<int&>, or widen a copack<int&>{x}.
copack<int, int&>{42} selects int, because int& cannot bind to a prvalue.
copack<int&, int const&>{x} selects int&, the less cv-qualified binding.
Widening admits reference alternatives as it does owning ones: copack<int, int&> b = copack<int&>{x}; is well-formed, as copack<int, long> a = copack<int>{1}; is today.
Carriers over reference alternatives
expected<copack<T&>, E>, choice<T&> and optional<copack<T&>> hold a pointer, not a reference, so the restriction on raw reference payloads in expected and choice does not apply to them. TYPE_ALGEBRA.md is updated accordingly.
Consequences
| over reference payloads of different types forms a sum of references: just<int&> | just<long&> is choice<int&, long&>.
Reference alternatives need a place in the canonical type order. Under LIBFN_CXX26, std::type_order decides it. The C++20 fallback may place them anywhere a sensible implementation allows, without additional complexity.
Out of scope
Binding to a temporary: as with optional<T&> and just<T&>, copack<int const&>{42} would dangle. Rejecting such bindings is tracked separately for all reference-holding carriers (#447).
copackrefuses reference alternatives. This blocks sums of borrowed values: in PR #437,just<int&> | just<long&>can only copy intochoice<int, long>, and anand_thenover a choice whose branches return different referencejusttypes is refused, because no copack can hold the reference results. This issue proposes admitting lvalue-reference alternatives, held as pointers, the wayjust<T&>andoptional<T&>hold their referents.Why this is a sum, unlike a reference to a copack
copack<A&, B&>is the sum of locations L(A)+L(B). EachA&has an injection into it, so the type is closed under the operations that form sums (|, the superset join). A reference to a copack,copack<A, B>&, has no such injections, which is why #434 remains open. Admitting reference alternatives also gives #434's snapshot distribution, L(A+B) → L(A)+L(B), a concrete target type: a borrowed copack can be distributed into a copack of references.Proposed semantics
T&is stored as a pointer toT. Rvalue-reference alternatives remain refused, as inpack,optionalandjust.T&for aT&alternative, regardless of the copack's value category or constness, as withjust<T&>. The tuple protocol for singular copacks (Add tuple protocol support for singular copacks #435) yields the same reference.just<T&>andoptional<T&>do.T,T&andT const&are distinct alternatives.copack_fordoes not merge them, so the distinction between owning, mutable and read-only access is preserved.packor acopackis not admitted as an alternative (copack<pack<A, B>&>), asjust<T&>andoptional<T&>refuse such referents: how a reference to a product or a sum takes part in conjunction, disjunction and grading is an open question.Construction
A value selects its alternative as overload resolution would select among functions taking each alternative type. Given
int x:copack<int&>{x}binds the reference.copack<int, int&>{x}is ambiguous and is rejected, asfoo(x)is ambiguous for overloadsfoo(int)andfoo(int&). Select the alternative explicitly withstd::in_place_type<int&>, or widen acopack<int&>{x}.copack<int, int&>{42}selectsint, becauseint&cannot bind to a prvalue.copack<int&, int const&>{x}selectsint&, the less cv-qualified binding.Widening admits reference alternatives as it does owning ones:
copack<int, int&> b = copack<int&>{x};is well-formed, ascopack<int, long> a = copack<int>{1};is today.Carriers over reference alternatives
expected<copack<T&>, E>,choice<T&>andoptional<copack<T&>>hold a pointer, not a reference, so the restriction on raw reference payloads inexpectedandchoicedoes not apply to them. TYPE_ALGEBRA.md is updated accordingly.Consequences
|over reference payloads of different types forms a sum of references:just<int&> | just<long&>ischoice<int&, long&>.and_thenadmits divergent reference branches, and the refusal added in PR Support lvalue-reference payloads injust#437 can be lifted.Canonical order
Reference alternatives need a place in the canonical type order. Under
LIBFN_CXX26,std::type_orderdecides it. The C++20 fallback may place them anywhere a sensible implementation allows, without additional complexity.Out of scope
Binding to a temporary: as with
optional<T&>andjust<T&>,copack<int const&>{42}would dangle. Rejecting such bindings is tracked separately for all reference-holding carriers (#447).Assisted-by: Claude:claude-opus-5-5