The Wyn type system — what we check and what we don't
Every language makes tradeoffs in its type system. Rust catches everything at compile time but makes you fight the borrow checker. Python catches nothing until runtime but lets you move fast. Go is somewhere in between.
Wyn is closer to Go's philosophy: catch the common bugs at compile time, don't make the programmer jump through hoops for the rest.
What wyn check catches
The type checker runs before compilation and catches these errors:
- Undefined variables and functions — typos, missing imports
- Type mismatches — assigning a string to an int variable, passing wrong types to functions
- Wrong argument counts — calling
add(1)when it expectsadd(1, 2) - Const reassignment — trying to modify a
constvariable - Missing return values — function declares
-> intbut doesn't return - Unused variables — warnings for declared-but-unused vars
- Unreachable code — code after a
returnstatement - Assignment in conditions —
if x = 5when you meantif x == 5
That's 8 categories of errors caught before your code runs. For most programs, this catches the bugs that actually matter.
What we don't catch
Some things slip through to runtime:
- Array index out of bounds — we check this at runtime with a helpful error message, not at compile time
- Null/nil access — Wyn doesn't have null, but some C interop can produce it
- Integer overflow — 64-bit integers, so this rarely matters in practice
- Some stdlib return types — a few stdlib functions default to
intin the checker when the return type isn't explicitly registered
We could add more static analysis. We chose not to, because every check we add is a check the programmer has to satisfy. We'd rather you ship working code today than fight the type system for a week.
The philosophy
From the Wyn flight rules:
If it compiles, it should work.
We take this seriously. The type checker is designed to catch the bugs that actually crash your program. It's not designed to prove your program is correct — that's your job.
The runtime adds a safety net: array bounds checking, stack overflow detection, and helpful error messages with line numbers. Between the compile-time checker and the runtime safety, most bugs are caught before they reach production.
What's next
We're working on:
- Better generic type inference (so
max(3, 7).to_string()works without a temp variable) - Trait bounds (
fn sort<T: Comparable>(arr)) - Exhaustive match checking
These will make the type system stricter over time, without breaking existing code. The goal is always the same: catch real bugs, don't create busywork.