prometeu-studio/docs/pbs/decisions/Dynamic Semantics - Branch Selection Decision.md
2026-03-24 13:42:18 +00:00

3.8 KiB

Dynamic Semantics - Branch Selection Decision

Status: Accepted (Implemented) Cycle: Initial branch-selection closure pass

1. Context

PBS v1 needs a closed runtime contract for if and switch before the dynamic semantics spec can be completed.

The remaining questions were:

  • whether conditions and selectors are evaluated once,
  • whether non-selected branches evaluate at all,
  • which selector categories are admitted for switch,
  • and whether branch selection itself may trap.

2. Decision

PBS v1 adopts the following branch-selection rules:

  1. if evaluates its condition exactly once.
  2. switch evaluates its selector exactly once.
  3. Only the selected branch or arm executes.
  4. Non-selected branches and arms perform no evaluation.
  5. if and switch are trap-free by themselves; only selected subexpressions may trap.
  6. switch is limited to statically discriminable selector categories.
  7. switch does not accept result, error, structs, string objects, or heap-backed types as selectors in v1.

3. if

For:

if cond { then_block } else { else_block }

the runtime behaves as follows:

  1. evaluate cond exactly once,
  2. if it yields true, execute only then_block,
  3. if it yields false, execute only else_block.

The non-selected branch is not evaluated, even partially.

Any trap associated with if arises only from:

  • evaluating cond,
  • or executing the selected branch.

4. switch

4.1 Selector evaluation

For:

switch selector { ... }

the runtime:

  1. evaluates selector exactly once,
  2. determines the matching arm using the canonical matching rule for the selector category,
  3. executes exactly one selected arm.

No non-selected arm is evaluated.

4.2 Admitted selector categories

In v1, switch is restricted to selector categories with static, deterministic matching behavior.

These include:

  • literal-comparable scalar values,
  • enum values,
  • str values with canonical static identity,
  • and other compile-time-constant-compatible selector categories only if explicitly admitted elsewhere.

switch does not accept:

  • result values,
  • error values,
  • structs,
  • string object/reference types distinct from canonical str,
  • or heap-backed selector categories.

Dynamic or structural matching belongs to a future match-style construct rather than to switch.

4.3 Matching rule

switch arm selection is exact and deterministic for the admitted selector type.

  • Enum selectors match by canonical enum-case identity.
  • Scalar selectors match by the exact equality rule already defined for that scalar category.
  • str selectors match by canonical static string identity rather than by heap-object comparison.

switch does not perform structural matching, guard evaluation, or user-defined equality dispatch.

5. Invariants

  • if and switch never evaluate more than one branch or arm.
  • Branch selection is deterministic for the same selector value.
  • switch remains a static discriminant-selection construct, not a result/error-processing construct.
  • Error processing with logic belongs to handle, not to switch.

6. Explicit Non-Decisions

This decision record does not yet close:

  • the final future design of match,
  • whether additional scalar-like selector categories will be admitted later,
  • the complete memory/cost wording associated with selector evaluation.

7. Spec Impact

This decision should feed at least:

  • docs/pbs/specs/9. Dynamic Semantics Specification.md
  • docs/pbs/specs/4. Static Semantics Specification.md
  • docs/pbs/specs/3. Core Syntax Specification.md

8. Validation Notes

The intended split is:

  • if and switch perform static, deterministic branch selection,
  • handle processes modeled result errors,
  • future dynamic or structural branching belongs to match, not to switch.