A compiled language for people who like Python
v1.21 The soundness release — 87 fixes in the gap between "no errors" and a working program → Wyn compiles to C and links a tiny runtime - no VM, no garbage collector. Memory is managed by reference counting, concurrency is spawn/await on coroutines, and a dependency is just a git URL.
struct Job { name: string ms: int fn report(self) -> string { return "${self.name} finished in ${self.ms}ms" } } fn run_job(name: string) -> int { return name.len() * 3 // stand-in for real work } fn main() { f1 = spawn run_job("resize") f2 = spawn run_job("transcode") jobs = [ Job{name: "resize", ms: await f1}, Job{name: "transcode", ms: await f2}, ] for j in jobs { print(j.report()) } }
Real program, real output - compiled on an Apple M3 Pro before publishing.
Measured on Apple M3 Pro - regenerate the req/s figure yourself with ./benchmarks/http_load.sh; method and details on the benchmarks page.
Project, tests, binary. Real output, with only the trailing next-step hints trimmed.
Every tab compiles as shown. The output pane is the program's actual output.
fn count_primes(lo: int, hi: int) -> int { count = 0 for n in lo..hi { if n < 2 { continue } prime = true d = 2 while d * d <= n { if n % d == 0 { prime = false; break } d = d + 1 } if prime { count = count + 1 } } return count } fn main() { // four cores, zero ceremony a = spawn count_primes(0, 1000000) b = spawn count_primes(1000000, 2000000) c = spawn count_primes(2000000, 3000000) d = spawn count_primes(3000000, 4000000) total = await a + await b + await c + await d print("primes below 4M: ${total}") }
Strings, arrays, and lambda results all chain through methods. Each snippet compiles as shown; the output line is the program's actual output.
result = "wyn, is, neat".split(",").map((s) => s.trim().upper()).join(" > ") print(result)
nums = [5, 3, 8, 1, 9, 2] top = nums.sort().reverse().slice(0, 3).sum() print(top)
words = ["compiler", "is", "an", "object", "pipeline"] caps = words.filter((s) => s.len() > 2).map((s) => s.upper()).join(" ") print(caps)
Automatic reference counting frees memory deterministically at scope exit. No pauses, no tuning flags, no runtime to install on the target machine.
spawn f() starts a coroutine; awaited tasks overlap cooperatively by default - no thread pool to size, no async coloring. 200 awaited 100ms sleeps finish in 104ms, not 20s, on a 12-core machine. Fire-and-forget spawn dispatches 1M tasks in ~0.7s.
wyn add web resolves to github.com/wynlang/web. Any host works, wyn.lock pins exact commits. No registry, no account, no publish step.
wyn bind header.h generates FFI bindings from a C header - proven against SQLite, lz4, and zstd. Forty years of C libraries, available directly.
Formatter, test runner, REPL, doc generator, LSP for VS Code and Neovim. One binary installs all of it.
Linux, macOS, Windows targets from one machine - plus iOS and Android builds from the same source. WebAssembly is not supported yet.
Opt in with [gpu] in wyn.toml and [float].map runs on Metal or OpenCL. Experimental: float32, single-op, off by default; a runtime cost model falls back to CPU, and on our M3 Pro it has not yet beaten the CPU path end-to-end, so treat it as a spike rather than a speedup. Binaries still run with no GPU.
The official web package is a thin layer over Wyn's native HTTP: parse the request, respond with a helper, spawn a handler per connection. The handler below loops, so the connection is reused: that sustains ~23,000 req/s with HTTP/1.1 keep-alive, and ~6,600 req/s when the client opens a fresh connection per request - zero failed requests either way, on an Apple M3 Pro. Reproduce both with ./benchmarks/http_load.sh.
import web fn handle(conn: int) { // One coroutine per CONNECTION: keep serving it // until the client hangs up (read_request -> ""). while true { req = web.read_request(conn) if req.len() == 0 { return } if web.is(req, "GET", "/") == 1 { web.html(req, 200, web.page("Hello", "<h1>Hello from Wyn</h1>", "")) } else { web.not_found(req) } } } fn main() { server = web.listen(8080) print("http://localhost:8080") while true { conn = web.accept(server) if conn > 0 { spawn handle(conn) } } }
An honest snapshot - including the rows we lose.
| Trait | Wyn | Go | Rust | Python |
|---|---|---|---|---|
| Native binary, no runtime install | ✓ | ✓ | ✓ | ✗ |
| No garbage collector | ✓ | ✗ | ✓ | ✗ |
| Sub-second builds | ✓ | ✓ | small crates only | - |
List comprehensions, slices, in | ✓ | ✗ | ✗ | ✓ |
| Lightweight spawn/await tasks | ✓ | ✓ | ✗ | ✗ |
Generators with yield | ✓ | ✗ | ✗ | ✓ |
| Mature ecosystem | ✗ | ✓ | ✓ | ✓ |
| Production track record | early | ✓ | ✓ | ✓ |

Every Wyn install ships with a wyvern in the error messages. Install it, break something, and Wynter will point you at the line.