Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

RFD-0006 — Three compute forms — expression, inline body, opaque FFI

Committed Opened 2026-05-03 · Committed 2026-05-03

Question

Domain-specific computation in Argon (capital-gain calculation, depreciation schedule, lease-term accrual, etc.) can be expressed at varying levels of complexity. How many implementation forms does compute admit, and what’s the tradeoff for each?

Decision

compute admits three implementation forms:

  1. Expression formcompute f(args) = expr. The body is a single expression. Suitable for one-shot calculations; lowers to a Core IR expression node.

  2. Inline body formcompute f(args) { input { … } out { … } ensure { … } body { … } }. The body is a constraint-sublanguage block expressed in Argon’s own grammar (RFD-0005). Lowers to CoreComputeBody::Inline. The inline interpreter (a tree walker over KernelExpr) dispatches inline bodies through DomainComputation via InlineComputeAdapter. Tier-classified. Dynamically loadable per-tenant without a Rust rebuild.

  3. Opaque Rust FFI formcompute f(args) { … impl rust("path::to::fn") }. The body is an opaque pointer to a registered Rust function. Lowers to CoreComputeBody::Rust. Requires a Rust rebuild; offers maximum flexibility and access to native libraries.

Form 2 dynamic loading uses an overlay mechanism: the kernel loads the inline-form body into a per-tenant registry at hydration time, and the inline adapter minter wires up dispatch. Per-tenant custom math ships without a code release.

Rationale

Three forms cover the cost-flexibility frontier. Expression form is easy to write, easy to read, easy to verify, but limited. Inline body form is more flexible (multi-statement, type-checked against Argon’s own expression grammar) and dynamically loadable, but tier-bounded. Rust FFI is unbounded but requires Rust expertise and a release cycle.

Form 2 is the load-bearing form for tenant customization. Tax law differs per jurisdiction. Tenants need to author math their own way without coordinating release cycles. The inline-body form lets that happen against Argon’s own grammar, with the same tier guarantees and the same provenance-tracking the language’s structural rules get.

Why not just two (expression + Rust). The middle ground matters: tenants are not Rust programmers. Inline body form gives them a mid-tier escape hatch — more than one expression, less than full Rust — that’s still tier-classified and provenance-tracked.

Why a tree walker, not a JIT. Inline-form bodies evaluate at kernel-runtime per-fact. JIT compilation would multiply complexity for marginal latency gains in a workload dominated by I/O and saturation passes. The tree walker keeps the evaluator small, debuggable, and consistent with the rest of the inline interpreter.

Consequences

  • Inline interpreter at crates/nous/src/runtime/interpreter.rs evaluates CoreComputeBody::Inline.
  • mint_inline_adapters_for_overlay runs at kernel-api hydration time to wire per-tenant adapters.
  • validate_compute_call_acyclicity rejects recursive compute-call cycles (OE0210). Arity mismatch surfaces as OE0208. Unresolved call targets surface as OE1406.
  • Compute-bodies compose: function calls (path(args)) over other computes, arithmetic over Int / Decimal / Money, multi-atom negation via aux-rule hoisting, complex-scrutinee match lowering.
  • Justification granularity is per-leaf-read with transparent combinators. Incremental recomputation has no interpreter-level cache; correctness defers to the kernel’s IVM substrate.