{
  "category": "Operators",
  "display_name": "Union of references (,)",
  "entry_kind": "built_in_operator",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.OP_UNION_REF",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Handled by the formula layer, which owns references; answers are recorded through whole formulas, not attributed to the operator.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": false,
    "state": "unmeasured",
    "state_label": "Implemented, no recorded answers attributed to it",
    "summary": "Implemented; no recorded answers are attributed to this entry",
    "workbook_corpus": null
  },
  "implementations": [
    {
      "commit": "9e1884369a678158dd82d3d74188daf986995e87",
      "flavour": "excel-compatibility-candidate",
      "language": "Rust",
      "name": "CalcFunc",
      "own_code": [
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-fml/src/eval/refops.rs#L100-L114"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "eval/refops::reference",
        "eval/refops::references"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-fml/src/eval/refops.rs#L100-L114",
      "state": "unmeasured",
      "suite": null,
      "summary": "Implemented; no recorded answers are attributed to this entry"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.OP_UNION_REF.json",
  "name": "OP_UNION_REF",
  "notes": [],
  "schema": "efh.function-reference/v1",
  "section_order": [
    "what-it-does",
    "try-it",
    "quirks",
    "how-to-implement",
    "version-differences",
    "alternatives"
  ],
  "sections": {
    "alternatives": "\n### Relationships\n\n\n- [`FUNC.OP_RANGE_REF`](FUNC.OP_RANGE_REF.md) — the bounding-box constructor; the join to\n  this operator's list.\n- [`FUNC.OP_INTERSECTION_REF`](FUNC.OP_INTERSECTION_REF.md) — the meet.\n- `AREAS` — the function that counts the members of a multi-area reference. It exists\n  essentially to inspect the output of this operator.\n- `INDEX` with a fourth argument — area selection within a multi-area reference.\n- `SUM`, `COUNT` and the other aggregates — the usual consumers, and the ones whose\n  double-counting behaviour on overlapping unions is worth checking.\n- The locale-dependent list separator is a *grammar* question. In locales where function\n  arguments are separated by `;`, whether the union operator is still spelled `,` is not\n  recorded in this Handbook's sources, and this page does not assert it.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\n- Represent a union as a first-class ordered list of areas, from the moment it is formed.\n  Flattening it to a bounding box, or to a string, loses the identity that `AREAS` and\n  `INDEX` depend on — which is precisely the seam `BUG-FUNC-003` describes.\n- Preserve member order, and materialize in member order.\n- Do not de-duplicate overlaps at formation time. Whether a consumer double-counts is the\n  consumer's semantics, and collapsing early removes the consumer's ability to decide.\n- Keep the operator distinct from the argument separator at every layer. If the same token\n  handling produces both, a parenthesized union and a two-argument call will eventually be\n  confused, and the failure will look like an arity bug rather than a reference bug.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n- **Materialization.** When a consumer needs values rather than a reference, the areas must\n  be combined. The contract records same-sheet rect-style multi-area materialization as\n  happening through resolver-driven row-vector combination in member order — that is, the\n  member order of the union decides the resulting value order.\n- **Cross-sheet unions.** The contract's admitted slice is same-sheet. Unions across sheets\n  are not covered by it, and are not settled here.\n- **Non-reference operands.** No union exists; the result is an error.\n- **Overlapping areas.** Preserved as written; see above.\n\n\n\n### Errors\n\n\n| Error | Condition |\n|---|---|\n| `#REF!` | An operand is not a usable reference, or a member area is invalid. |\n| any incoming error | An error operand propagates. |\n\n`data/functions/FUNC.OP_UNION_REF.json` records no Microsoft documentation URL (`docs` is\n`null`).\n\n\n",
    "sources": "- `data/presence/FUNC.OP_UNION_REF.json` — implementing module\n  `earlier-implementation/operator_reference_family.rs`.\n- Handbook `content/model/01-value-universe.md` (reference shapes, including multi-area),\n  `03-call-pipeline.md` (operators are functions; parse-only delimiters are not).\n\n",
    "version-differences": "No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.",
    "what-it-does": "\n`A , B` takes two references and returns a reference designating **both** areas — a\nmulti-area reference, not a merged rectangle.\n\nTwo consequences that a reader can observe:\n\n- **Areas keep their identity.** The contract records `INDEX((A1:A2,B1:B2),2,1,2)` selecting\n  from the *second* area — `INDEX`'s fourth argument is an area number, which only means\n  something because the union preserved the areas separately. Any function taking an area\n  index (`INDEX`, `AREAS`) is consuming exactly this structure.\n- **Overlaps are not de-duplicated.** A union is a list of areas, not a set of cells. The\n  contract's `SUM((A1,B1))` finding is a plain two-cell sum, but a union whose areas overlap\n  presents the overlapping cells more than once to a consumer that scans areas in order.\n  Whether every consumer double-counts is a per-function question, and the Handbook has not\n  recorded it.\n\n**The parenthesis requirement is not decoration.** Inside a function call, a comma is the\nargument separator — grammar, not an operator (chapter 03: parse-only delimiters carry no\nsemantics and get no function identity). `SUM(A1,B1)` is a two-argument call; `SUM((A1,B1))`\nis a one-argument call whose argument is a union. Both happen to total the same cells here,\nwhich is exactly why the distinction is so easy to miss, and why it bites when the consuming\nfunction counts its arguments (`AREAS`, `INDEX`, `SUBTOTAL`).\n\n\n\n### Arguments\n\n\n| Position | Name | Meaning |\n|---|---|---|\n| 0 | `A` | First reference. Required. |\n| 1 | `B` | Second reference. Required. |\n\nArity is exactly 2; no optional arguments, no defaults. A chain `(A1,B1,C1)` is repeated\napplication of the two-argument operator, and area order is preserved — so the operator is\nnot commutative in the way a set union would be, because area *order* is observable through\narea-indexed consumers.\n\nBoth operands must be reference-shaped.\n\n\n"
  },
  "signature": {
    "display": "A, B",
    "parameters": [],
    "trailing_repeats": null
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "formula_layer",
        "reason": null
      },
      "arity": {
        "max": 2,
        "min": 2
      },
      "category": "Operators",
      "classification": {
        "arg_preparation_profile": "RefsVisibleInAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "fec_dependency_profile": "RefOnly",
        "host_interaction_class": "WorkbookState",
        "kernel_signature_class": "Custom",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": null,
        "short_source": "no-short-description"
      },
      "docs": null,
      "entry_kind": "built_in_operator",
      "localized_family_names": null,
      "localized_names": [],
      "signature": {
        "display": "A, B",
        "parameters": [],
        "trailing_repeats": null
      },
      "surface_name": "OP_UNION_REF",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": null
  },
  "try_it": {
    "formula": "=SUM((B2,B4))",
    "inputs": {
      "B2": 1,
      "B4": 3
    }
  },
  "url": "https://handbook.dnacalc.com/functions/OP_UNION_REF.html",
  "variants": [],
  "versions": []
}