[series] Step 2 — SoA record-of-series #62

Open
opened 2026-06-02 12:00:23 +02:00 by Brummel · 1 comment
Owner

Second tier of the series milestone (#8), downstream of step 1 (#61). A record-valued Series stored struct-of-arrays (column-major), the efficient layout for streaming analytics where a query scans one field across many ticks.

Direction (milestone decision D3, to confirm at brainstorm)

Lean: record-of-series composition — an AILang ADT bundling N primitive Series, one column per record field, e.g. (ctor PVS (con Series Float) (con Series Int)). Preferred over 0007's RawBuf-internal record-element intercept because it keeps step 2 pure library-extension (zero Rust) and makes step-1 primitive Series the literal building block.

Open design forks for the step-2 brainstorm

  • Composition (record-of-series, pure AILang) vs 0007's RawBuf-internal SoA intercept (Rust base-extension work). D3 leans composition.
  • Structural records ({price: Float, volume: Int}) vs nominal data ADTs — decides how at types its materialised record return. Under SoA the return is always a freshly materialised own record; no borrow is possible (no contiguous object to borrow — milestone decision D1).

Anchor: design/models/0007-kernel-extensions.md §"Forward axis: SoA for records". Do not start before step 1 closes.

Second tier of the `series` milestone (#8), downstream of step 1 (#61). A record-valued Series stored struct-of-arrays (column-major), the efficient layout for streaming analytics where a query scans one field across many ticks. ## Direction (milestone decision D3, to confirm at brainstorm) Lean: record-of-series *composition* — an AILang ADT bundling N primitive Series, one column per record field, e.g. `(ctor PVS (con Series Float) (con Series Int))`. Preferred over 0007's RawBuf-internal record-element intercept because it keeps step 2 pure library-extension (zero Rust) and makes step-1 primitive Series the literal building block. ## Open design forks for the step-2 brainstorm - Composition (record-of-series, pure AILang) vs 0007's RawBuf-internal SoA intercept (Rust base-extension work). D3 leans composition. - Structural records (`{price: Float, volume: Int}`) vs nominal `data` ADTs — decides how `at` types its materialised record return. Under SoA the return is always a freshly materialised `own` record; no borrow is possible (no contiguous object to borrow — milestone decision D1). Anchor: `design/models/0007-kernel-extensions.md` §"Forward axis: SoA for records". Do not start before step 1 closes.
Brummel added this to the series milestone 2026-06-02 12:00:23 +02:00
Brummel added the feature label 2026-06-02 12:00:23 +02:00
Author
Owner

Grounding finding (brainstorm, 2026-06-02): the premise that step 2 is a pure-AILang library extension does not hold.

AILang is nominal-only: the core Type enum is Con/Fn/Var/Forall — no structural-record or row type. A generic 'Series r' over an arbitrary record r is therefore not expressible in pure AILang; there is no row variable to abstract the record's fields over.

Consequences:

  • Composition (D3) is per-record, hand-written: the author defines a nominal bundle ADT (e.g. (data PVS (ctor PVS (con Series Float) (con Series Int)))) plus distribute/gather push/at. This DOES achieve the column-major SoA layout (one RawBuf per field) and the streaming-analytics goal — but it yields no reusable generic type and adds no kernel mechanism. As a 'feature' it is thin (essentially 'use Series twice' + a worked example).
  • A generic, ergonomic record-Series — the thing that would be a real feature — needs base-tier work: either the RawBuf-internal SoA intercept sketched in design/models/0007 §'Forward axis: SoA for records' (Rust codegen, introspecting the record ADT's fields), or introducing structural records to the language (a surface AILang otherwise cuts).

Therefore step 2 is NOT a pure-library step; it is a base-tier/language decision, not the library step it was framed as. DEFERRED pending that decision. The series milestone closes cleanly at the shipped, leak-clean primitive step 1.

The issue's 'at return: structural vs nominal record' fork is resolved by the grounding fact: any materialised record must be a nominal ADT (D1: freshly materialised own).

Grounding finding (brainstorm, 2026-06-02): the premise that step 2 is a pure-AILang library extension does not hold. AILang is nominal-only: the core Type enum is Con/Fn/Var/Forall — no structural-record or row type. A generic 'Series r' over an arbitrary record r is therefore not expressible in pure AILang; there is no row variable to abstract the record's fields over. Consequences: - Composition (D3) is per-record, hand-written: the author defines a nominal bundle ADT (e.g. (data PVS (ctor PVS (con Series Float) (con Series Int)))) plus distribute/gather push/at. This DOES achieve the column-major SoA layout (one RawBuf per field) and the streaming-analytics goal — but it yields no reusable generic type and adds no kernel mechanism. As a 'feature' it is thin (essentially 'use Series twice' + a worked example). - A generic, ergonomic record-Series — the thing that would be a real feature — needs base-tier work: either the RawBuf-internal SoA intercept sketched in design/models/0007 §'Forward axis: SoA for records' (Rust codegen, introspecting the record ADT's fields), or introducing structural records to the language (a surface AILang otherwise cuts). Therefore step 2 is NOT a pure-library step; it is a base-tier/language decision, not the library step it was framed as. DEFERRED pending that decision. The series milestone closes cleanly at the shipped, leak-clean primitive step 1. The issue's 'at return: structural vs nominal record' fork is resolved by the grounding fact: any materialised record must be a nominal ADT (D1: freshly materialised own).
Brummel removed this from the series milestone 2026-06-02 17:53:01 +02:00
Sign in to join this conversation.