Files
hakorune/docs/design/null-missing-boxes.md

2.6 KiB

NullBox / MissingBox — Design and Rollout (Observe → Adopt)

Status: proposal accepted for dev-only observation; defaults unchanged

Goals

  • Make “absence of value” explicit and observable without changing prod behavior.
  • Separate “explicit null” from “missing/unset” to improve diagnostics, reduce ambiguity, and simplify downstream policies.
  • Stage the rollout via Observe → Adopt: enable metrics in dev, verify zero-diff on outputs, then adopt selectively.

Terms

  • Null = explicit no-value. Represented by NullBox (stringify: "null").
  • Missing = absent/unset (missing key, uninitialized). Represented by MissingBox (stringify: "(missing)" in dev only; not surfaced in prod).
  • Bottom/void (unreachable/side-effect-only) is NOT materialized as a box. Using it as a value is a bug (trap).

Behavior (policy sketch)

  • Equality: Null == Null → true. Missing: comparison is error.
  • Ordering (<, <=, >, >=): Null and Missing → error.
  • Arithmetic: Null propagates (returns Null) or errors when NYASH_NULL_STRICT=1. Missing → error.
  • Coalesce ??: Null ?? x = x, Missing ?? x = x.
  • Safe-call ?.: Null?.m() = Null; Missing?.m() = Missing (or error by policy).

Note: language operators ??/?. may be introduced later; initial staging can use functions or Operator Boxes.

Implementation plan (minimal, reversible)

  1. Types (done, dev scope only)

    • Add NullBox (already present) and MissingBox (new) as first-class boxes.
    • No change to default value mapping: VM maps NullBox to VMValue::Void for backward compatibility.
  2. Env toggles

    • NYASH_NULL_MISSING_BOX=1: enable observation path (no default behavior changes).
    • NYASH_NULL_STRICT=1: strict policy (operators error on null) — effective only when the first flag is enabled.
  3. VM integration (dev-only observation)

    • Classification helpers recognize BoxRef(NullBox/MissingBox) for traces.
    • Print: Void and BoxRef(VoidBox) → "null"; BoxRef(NullBox) prints via box toString ("null"); MissingBox prints "(missing)" in dev.
    • Compare/Add: no default behavior changes; strict behavior is gated behind envs and will be staged later.
  4. JSON/Node integration (later)

    • Optional: when flag is on, object_get/array_get may return MissingBox for absent entries, while null remains NullBox.
    • UI/print normalization can translate Missing → null at boundaries based on policy.

Acceptance

  • Defaults unchanged (prod): no output or semantic differences.
  • Dev-only path provides metrics and safe diagnostics; quick/integration smokes remain green.
  • After stability, selective adopt in Compare/Add can be enabled (Compare already adopted by default).