Classes → dataclass
class User: → @dataclass(slots=True). model User: → Pydantic BaseModel. class! → bare class with synthesised __init__. Details →
Typhon is a compile-to-Python language. Each Typhon construct lowers to an explicit, readable Python form — the same code an experienced Pythonista would have written by hand. This section maps every Typhon-specific form to its emitted Python.
.ty source │ ▼ tyc-syntax (lex + parse) ▼ tyc-resolve (name resolution, let/mut classification) ▼ tyc-types (type check, narrowing) ▼ tyc-analyse (purity, async, comptime, auto-gather) ▼ tyc-desugar (Typhon AST → Python AST: merge impl, expand ?, lower gather/go, ...) ▼ tyc-emit (Python source + .py.map) ▼ tyc-format (ruff format post-process) ▼ .py + .sourcemaps/*.py.map + (typhon_runtime/*.py if used)See Architecture Overview for the compiler internals.
Classes → dataclass
class User: → @dataclass(slots=True). model User: → Pydantic BaseModel. class! → bare class with synthesised __init__. Details →
Result → typhon_runtime
Result[T, E], Ok, Err lower to frozen dataclasses in a generated typhon_runtime module. ? lowers to inline isinstance(_t, Err): return _t. The rescue boundary sugar lowers to try_result(...)? (postfix) or a try / except … return Err(...) block. Details →
gather: → TaskGroup
gather: lowers to asyncio.TaskGroup. gather(strategy="best-effort"): lowers to asyncio.gather(..., return_exceptions=True). Details →
go → spawn registry
go f(x) lowers to typhon_runtime.tasks.spawn(f(x)) — strong-ref registry prevents GC mid-flight. Details →
lazy → proxies
lazy import np = numpy → bespoke __TyphonLazy_np_ proxy class. lazy let X → sentinel-cached lazy_let (imported as __typhon_lazy_let) at module scope; @cached_property at class scope. The lazy[T] return-type form is roadmapped. Details →
comptime → inlined literals
comptime let PORT = int(env("PORT", "8080")) → PORT: int = 8080 after sandbox evaluation. Details →
extend → free functions
extend str: def to_slug(): ... → def __typhon_ext_str__to_slug(self): ... with call-site rewrites for statically-annotated receivers. Details →
Source maps
Each emitted .py ships with a .py.map v2 file recording per-statement (out_line → ty_line) for tyc trace and the LSP. Details →
Three rules guide every lowering decision:
Result ADT, the lazy-import proxy, the strong-ref task registry), the code emits as local typhon_runtime/ source. Production servers do not install Typhon-specific anything..ty. Per-statement (out_line → ty_line) tables let tyc trace remap tracebacks, and let the LSP do cross-file go-to-definition across the .ty / .py boundary.When you tyc build, the emitted tree contains:
build/<your modules>.py — your compiled source.build/.sourcemaps/<your modules>.py.map — source maps (moved under .sourcemaps/ in v0.6.1; the legacy adjacent layout is still readable).build/typhon_runtime/ — only when you use features that need it:
result.py — Ok, Err, Result + combinators and try_result.tasks.py — spawn(coro) with the strong-ref _BACKGROUND set.lazy.py — lazy_let(lambda: ...) + the _LazyValue proxy.freeze.py, cast.py, parallel.py, traceback.py, stdlib.py — freeze let, as!, auto-parallel, [emit] traceback-remap, and internal helpers. See The typhon_runtime module.build/<your modules>.pyi — for every .dty you wrote.Nothing else. No __pycache__/ (Python creates that at runtime), no Cargo artefacts, no Typhon-marker files.
Drill into a specific lowering: