Skip to content

Feat: TypedPython fixed-layout classes (N-11) - #124

Merged
b-re-w merged 12 commits into
developfrom
feat/typedpython-classes
Oct 3, 2026
Merged

b-re-w merged 12 commits into
developfrom
feat/typedpython-classes

Conversation

@b-re-w

@b-re-w b-re-w commented Oct 3, 2026

Copy link
Copy Markdown
Member

Closes #123

Features added

  • Front end: lowers ClassDecl (only for user-written __slots__), None, is/is not, class-typed parameters (C, C | None), FieldGet/FieldSet, New for a trivial __init__. A rejected class gets a reason in Module.skipped.
  • Verifier: class and field existence, New arity, exact-type proof for every field access (the accepted forms are listed in the verify.py docstring), purity/deopt, ownership.
  • C back end and runtime: the class is captured at init (heap type, no __dict__, member descriptors made for exactly that class). Each slot access checks the exact type and tp_version_tag; each New checks the global through a module-dict watcher, or a dict lookup when no watcher id is free. A mismatch takes the generic path (impure functions) or deopts (pure functions). Param.cls guards also run on direct C-to-C calls.

Documentation corrected

  • SPEC N-11: status, post-init change semantics, and a slot-writing function is never closed.
  • ir.py: class-param calls can deopt.
  • runtime/API.md: the new helpers.

Tests added: front end, verifier, cgen classes, and 17 class-change scenarios (each compared against the interpreted module, crash cases in subprocesses), plus ASan/UBSan runs. Red and mutation results are in the branch commits' reports.

Benchmark: binary-trees' Node declares __slots__; run.py adds a CPython (no __slots__) column, and in interleaved per-pair no-slots times. make and check compile; run.py verify agrees across all five benchmarks.

Verification (local, macOS arm64, CPython 3.14.7): the full TypedPython suite gives 934 passed, 3 skipped, EXIT=0.

Pending: the interleaved before/after measurement of the per-access checks (binary-trees and nbody) is waiting for a quiet machine (load 20–40). Results will be posted here.

@b-re-w

b-re-w commented Oct 3, 2026

Copy link
Copy Markdown
Member Author

Before/after measurement of the per-access class checks (4987883 vs 11e52af), interleaved: each pair runs compiled(before) and compiled(after) in alternating order, plus CPython. 11 pairs per benchmark, default sizes, macOS arm64, CPython 3.14.7. Load was 9–13, so read the ratios, not absolute times.

benchmark after / before, median range speedup vs CPython (slots), before → after 1-min load
binary-trees 1.072 0.797–1.190 1.8x → 1.7x 10.0–12.8
nbody (control, no class ops) 0.976 0.790–1.226 30.4x → 29.1x 8.8–10.0
  • The checks cost binary-trees about 7% at the median. The per-pair spread (±20%) is larger than that, so 7% is an upper estimate under this load, not a precise figure.
  • nbody has no class operations and moves by −2.4%, which is the noise floor of this run.
  • Outputs were identical in every pair.
  • binary-trees' compiled speedup is only 1.7–1.8x, because the benchmark is dominated by allocation and GC tracking of each Node (tp_alloc), which compiled and interpreted code pay alike. The checks are not inside loops, since check reads two fields per call, so hoisting would not change this.
  • Raw data: per-pair times and load in the run's JSON (kept locally).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant