prometeu-studio/docs/agendas/Dynamic Semantics - Effect Surfaces Agenda.md
2026-03-24 13:42:17 +00:00

3.7 KiB

Dynamic Semantics - Effect Surfaces Agenda

Status: Working agenda (pre-spec)
Purpose: close the runtime behavior of PBS effect and control surfaces before drafting the dynamic semantics spec

1. Context

PBS v1 already commits to several user-visible effect surfaces:

  • optional,
  • result<E>,
  • apply,
  • bind,
  • switch,
  • if,
  • else,
  • handle,
  • ! result propagation.

Static semantics explains where these forms are legal. What is still missing is the runtime contract: evaluation timing, payload extraction behavior, propagation order, and interaction with traps and allocation.

2. Decisions to Produce

This agenda must end with decisions for:

  1. The runtime value model of optional and result<E>.
  2. The evaluation and propagation semantics of apply, bind, else, !, and handle.
  3. The runtime branch-selection model for if and switch.
  4. The exact boundary between explicit status values and true runtime traps.

3. Core Questions

Q1. optional

  • Is some(expr) evaluated eagerly before container construction?
  • Does opt else fallback evaluate fallback only on none?
  • Is optional guaranteed trap-free at runtime except for traps produced by evaluating its subexpressions?

Q2. result<E>

  • Is ok(...) / err(...) purely a return-flow construct with no standalone runtime value form in v1?
  • How exactly does expr! propagate failure through the enclosing function?
  • Does handle expr { ... } first evaluate expr, then dispatch exactly one remapping arm, or are there any hidden intermediate forms?

Q3. apply

  • Is direct-call sugar defined entirely through canonical apply, including runtime order?
  • When apply resolves to a callback, method, contract implementation, or host-backed callable, what runtime steps are shared and what remains callable-specific?
  • Must apply preserve a single common trap model regardless of callable kind?

Q4. bind

  • What runtime artifact does bind(context, fn_name) produce: a nominal callback pair, hidden object, or other VM-level value category?
  • Is the context expression always evaluated exactly once at bind time?
  • Does bind itself allocate, and if yes, must that be part of the visible cost contract?

Q5. switch and if

  • Is the selector/condition evaluated exactly once before branch selection?
  • Does switch compare enum cases and scalar literals via a single equality model, or are there construct-specific rules?
  • Are non-selected arm blocks guaranteed not to evaluate at all?

Q6. Status values vs traps

  • Which user-visible failures must stay in optional / result space instead of trapping?
  • Are there any operations over these surfaces that may still trap despite their explicit effect model?

Q7. Allocation and copy visibility

  • Which of these constructs may allocate, copy, or retain heap state as part of normal execution?
  • Which of those costs must be reflected later by the diagnostics spec?

4. Expected Spec Material

After discussion, this agenda should directly feed sections of Dynamic Semantics Specification.md covering:

  1. runtime values and carrier forms,
  2. call and callback execution,
  3. effect propagation and remapping,
  4. conditional and branching execution,
  5. trap versus status-value behavior for effect-bearing constructs.

5. Non-Goals

  • Revisiting the static typing surface already settled in 4. Static Semantics Specification.md.
  • Designing collection APIs or general async/error subsystems.
  • Reopening reserved syntax such as future match.

6. Inputs

  • 3. Core Syntax Specification.md
  • 4. Static Semantics Specification.md
  • Heap Model - Agenda.md
  • Dynamic Semantics - Execution Model Agenda.md