Skip to content

A compiled language for people who like Python

Feels like Python.Runs like C.Ships as one binary.

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() {
    var f1 = spawn run_job("resize")
    var f2 = spawn run_job("transcode")

    var jobs = [
        Job{name: "resize", ms: await f1},
        Job{name: "transcode", ms: await f2},
    ]

    for j in jobs {
        println(j.report())
    }
}
$ wyn run jobs.wyn
Compiled in 392ms
resize finished in 18ms
transcode finished in 27ms

Real program, real output — compiled on an Apple M4 before publishing.

~0.4s
hello-world build
<1s
full rebuild
~5μs
spawn + await
49KB
hello-world binary
7,000
req/s · web pkg, c=200

Measured on Apple M4 — method and details on the benchmarks page.

Zero to running

Project, tests, binary. The terminal transcripts below are unedited.

wyn new
$ wyn new myapp --template cli
✓ Created cli project: myapp/
myapp/wyn.toml
myapp/src/main.wyn
myapp/tests/test_main.wyn
myapp/README.md
wyn test
$ cd myapp && wyn test
Scanning: tests/
✓ starts_with
✓ upper
✓ split
✓ file roundtrip
4 tests passed
wyn build
$ wyn build src/main.wyn
✓ Built: src/main (53KB, 336ms)
$ ./src/main
myapp v0.1.0
Usage: myapp <command> [options]

The language in five tabs

Every tab compiles as shown. The output pane is the program's actual output.

fn count_primes(lo: int, hi: int) -> int {
    var count = 0
    for n in lo..hi {
        if n < 2 { continue }
        var prime = true
        var 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
    var a = spawn count_primes(0, 1000000)
    var b = spawn count_primes(1000000, 2000000)
    var c = spawn count_primes(2000000, 3000000)
    var d = spawn count_primes(3000000, 4000000)

    var total = await a + await b + await c + await d
    println("primes below 4M: ${total}")
}
$ wyn run example.wyn
primes below 4M: 283146
Edit in playground ↗

No VM, no GC

Automatic reference counting frees memory deterministically at scope exit. No pauses, no tuning flags, no runtime to install on the target machine.

Concurrency built in

spawn f() starts a coroutine; await collects the result. Cooperative I/O under the hood, ~5μs per spawn+await round trip.

Packages are git repos

wyn add web resolves to github.com/wynlang/web. Any host works, wyn.lock pins exact commits. No registry, no account, no publish step.

C is one import away

wyn bind header.h generates FFI bindings from a C header — proven against SQLite, lz4, and zstd. Forty years of C libraries, available directly.

Tooling in the box

Formatter, test runner, REPL, doc generator, LSP for VS Code and Neovim. One binary installs all of it.

Cross-compile anywhere

Linux, macOS, Windows targets from one machine — plus iOS, Android, and WebAssembly builds from the same source.

A web server is a for loop

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. It sustains ~7,000 req/s at 200 concurrent connections with zero failed requests on an Apple M4 — with keep-alive work in flight to push that much higher.

$ wyn pkg add web
$ wyn run server.wyn
http://localhost:8080
server.wyn
import web

fn handle(conn: int) {
    var 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() {
    var server = web.listen(8080)
    println("http://localhost:8080")
    while true {
        var conn = web.accept(server)
        if conn > 0 { spawn handle(conn) }
    }
}

Where Wyn stands

An honest snapshot — including the rows we lose.

TraitWynGoRustPython
Native binary, no runtime install
No garbage collector
Sub-second builds
List comprehensions, slices, in
Lightweight spawn/await tasks
Generators with yield
Mature ecosystem
Production track recordearly

Meet Wynter

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

MIT License — v1.18