Skip to content

Wyn vs Rust

Wyn and Rust both compile to native code without a garbage collector. But they make very different tradeoffs. Rust prioritizes zero-cost abstractions and memory safety guarantees. Wyn prioritizes fast compilation, simple syntax, and a batteries-included stdlib.

Quick Facts

WynRust
First release20252015
Compiles toC (then native binary)Native binary (LLVM)
Memory managementARC (automatic)Ownership + borrow checker
Hello world binary50KB~421KB
Compile time (hello, dev)356ms~357ms (cargo build, clean)
Learning curveLow (Python-like)High (ownership, lifetimes, borrows)
Unsafe codeNot neededSometimes needed

Benchmark Comparison

All benchmarks re-measured for Wyn 1.21.0 - the published release tarball, built with --release - against Rust 1.96.0 (rustc -O / cargo build --release), on Apple M3 Pro, macOS 26, in one session on one machine. Wall-clock for the whole process, so a ~7ms startup floor is included in both languages' rows. Compile-time rows delete the output first, so every one is a real build.

BenchmarkWynRust
fib(35) recursive41.6ms44.6ms
Hello world startup6.9ms7.3ms
Hello world binary50KB421KB (431,416 bytes)
Hello world peak RSS1.4MB1.5MB
Compile time (hello, dev)356ms357ms (cargo build, clean)
Compile time (hello, --release)1.18s368ms (cargo, clean)
Compile time (hello, single file)356ms (wyn build)185ms (rustc -O)

An honest correction to an earlier version of this page: Rust is not uniformly faster on compute here, and Wyn does not compile 7–15x faster than Rust on small programs. On this recursive benchmark Wyn edges Rust out by ~7% (both are just optimized native code), and cargo build --release on hello world is three times faster than wyn build --release, because Wyn's release path shells out to clang -O3 and pays for it. Dev builds are now a dead heat - Wyn's dev figure went from 288ms to 356ms not because anything got slower but because the old number was measured in a source checkout carrying a precompiled header, which the release tarball deliberately does not ship. Expect Rust's LLVM optimizer to win on tight numeric loops where its aliasing information is better than what C output gives clang.

Syntax Comparison

Structs and Methods

rust
// Rust
struct User {
    name: String,
    age: u32,
}

impl User {
    fn is_adult(&self) -> bool {
        self.age >= 18
    }

    fn greeting(&self) -> String {
        format!("Hi, {}!", self.name)
    }
}

fn main() {
    let user = User { name: String::from("Alice"), age: 25 };
    println!("{}", user.greeting());
}
wyn
// Wyn
struct User {
    name: string
    age: int

    fn is_adult(self) -> bool {
        return self.age >= 18
    }

    fn greeting(self) -> string {
        return "Hi, ${self.name}!"
    }
}

fn main() {
    user = User{name: "Alice", age: 25}
    print(user.greeting())
}

No impl blocks, no String::from(), no &self vs self distinction, no format! macro. Wyn strings are reference-counted - you don't think about ownership.

Error Handling

Both languages use Result types. Rust has the ? operator, Wyn uses pattern matching.

rust
// Rust
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("division by zero".to_string())
    } else {
        Ok(a / b)
    }
}

fn main() {
    match divide(10.0, 3.0) {
        Ok(v) => println!("result: {v}"),
        Err(e) => println!("error: {e}"),
    }
}
wyn
// Wyn
fn divide(a: int, b: int) -> Result<int, string> {
    if b == 0 { return Err("division by zero") }
    return Ok(a / b)
}

fn main() {
    match divide(10, 3) {
        Ok(v) => print("result: ${v}")
        Err(e) => print("error: ${e}")
    }
}

Similar pattern, but Wyn doesn't require .to_string(), semicolons, or turbofish syntax.

Concurrency

Both languages make you be explicit about shared mutable state; they differ in when you find out. Rust rejects unsynchronised sharing at compile time - you reach for Arc<Mutex<T>> or a channel because the borrow checker will not let you do otherwise. Wyn has no borrow checker, so it enforces the same rule dynamically: mutating a shared array, HashMap or HashSet from two tasks panics with the fix named, mutating a shared scalar global is a compile-time error, and to share mutable state on purpose you use Shared or a channel.

Be clear about which guarantee is stronger. Rust's is static and total. Wyn's covers writer-vs-writer only - a read concurrent with a write is still unguarded - and a panic is a crash you did not want, discovered in production rather than in the compiler. What Wyn buys is that spawn/await needs no Arc, no Mutex, no lifetime annotations and no async coloring for the common case, which is tasks that do not share mutable state:

rust
// Rust
use std::thread;

fn fib(n: u64) -> u64 {
    if n <= 1 { return n; }
    fib(n - 1) + fib(n - 2)
}

fn main() {
    let handles: Vec<_> = (0..4)
        .map(|_| thread::spawn(|| fib(38)))
        .collect();

    let total: u64 = handles
        .into_iter()
        .map(|h| h.join().unwrap())
        .sum();

    println!("total: {total}");
}
wyn
// Wyn
fn fib(n: int) -> int {
    if n <= 1 { return n }
    return fib(n - 1) + fib(n - 2)
}

fn main() {
    a = spawn fib(38)
    b = spawn fib(38)
    c = spawn fib(38)
    d = spawn fib(38)
    print((await a + await b + await c + await d).to_string())
}

No Vec<_>, no .collect(), no .join().unwrap(). Wyn's spawn returns a typed future, await gets the value. Neither task above touches shared state, which is why neither language needs a lock for it.

Memory Model

This is the biggest difference between the two languages.

Rust uses ownership and borrowing. Every value has exactly one owner. References must follow strict lifetime rules. The borrow checker catches data races and use-after-free at compile time - but it also rejects valid programs and has a steep learning curve.

Wyn uses Automatic Reference Counting (ARC). Values are reference-counted and freed when the count reaches zero. No ownership rules to learn, no lifetime annotations, no borrow checker fights. The tradeoff: ARC can't detect reference cycles (rare in practice), and atomic reference counting adds a small overhead (~2-5% on benchmarks).

For most applications - CLI tools, web servers, data processing - ARC is the right tradeoff. You get deterministic memory management without GC pauses and without fighting the compiler.

When to Choose Wyn

  • You want a simple, predictable build - wyn build is ~360ms for anything up to a few thousand lines, with no dependency-tree compile cost (and wyn check type-checks 1,000 lines in 14ms)
  • You want a simple memory model without ownership, lifetimes, or borrow checking
  • You want a batteries-included stdlib (HTTP, SQLite, JSON, bcrypt, GUI)
  • You're building CLI tools, web APIs, or scripts where Rust's safety guarantees are overkill
  • You want tiny binaries (50KB vs ~421KB)
  • You want to be productive in your first hour without reading a 500-page book

When to Choose Rust

  • You're building safety-critical systems where memory bugs are unacceptable
  • You need zero-cost abstractions and maximum runtime performance
  • You're writing OS kernels, embedded firmware, or browser engines
  • You need the crates.io ecosystem with 140,000+ packages
  • You want compile-time guarantees about data races and memory safety
  • You're building libraries that will be used by millions of developers

Compile Time

Compile time matters more than most benchmarks, because you pay it hundreds of times a day. Here is how Wyn scales, measured on this machine:

Project sizewyn checkwyn buildwyn build --release
Hello world12ms356ms1.18s
500 LOC12ms359ms1.19s
1,000 LOC14ms376ms1.20s
5,000 LOC33ms505ms1.32s

Wyn's two-stage compilation (Wyn → C → binary) scales well: the Wyn-to-C step is a single-pass transpiler, and most of the wall time is the C compiler invocation, which is close to constant for programs of this size.

An earlier version of this page published a Wyn-vs-Rust compile-time table with Rust at 3s–45s. We could not reproduce those Rust numbers and have removed the table. On equivalent synthetic programs of 500–5,000 lines, cargo build --release finished in 0.35s–0.57s on this machine - faster than Wyn. Rust's reputation for slow builds comes from real projects with heavy generics, macros, trait resolution and large dependency trees, not from lines of code; we don't have a defensible apples-to-apples measurement of that, so we're not going to publish a number for it.

Try Wyn

sh
curl -fsSL https://wynlang.com/install.sh | sh
wyn run hello.wyn

See Also

MIT License - v1.21.0