Skip to content

Allow lvalue-reference alternatives in copack #448

Description

@Bronek

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&>.
  • The superset join in and_then admits divergent reference branches, and the refusal added in PR Support lvalue-reference payloads in just #437 can be lifted.

Canonical order

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).

Assisted-by: Claude:claude-opus-5-5

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestrelease-0.2Planned for release 0.2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions