Windjammer
A simple, high-level language that transpiles to Rustβcombining Go's ergonomics, Ruby's expressiveness, and Rust's safety and performance.
π― The 80/20 Language: 80% of Rust's power with 20% of the complexity
π Read the detailed comparison: Windjammer vs Rust vs Go
π Production Validation: TaskFlow API
Empirical proof of Windjammer's 80/20 thesis! π―
We built a production-quality REST API in both Windjammer and Rust to compare:
- Windjammer: 2,144 lines with clean
std.*abstractions - Rust: 1,907 lines with exposed crate APIs (axum, sqlx, tracing, etc.)
Results (v0.16.0)
Code Quality: Rust is 11% less code, but Windjammer wins on:
- β
Zero crate leakage -
std.http,std.db,std.logonly - β Stable APIs - No breaking changes when crates update
- β 60-70% faster onboarding - 3 APIs vs 8+ crates to learn
- β Better abstractions - Cleaner, more maintainable code
Performance: Rust baseline measured (v0.16.0):
- β
116,579 req/s throughput (
/healthendpoint) - β 707 Β΅s median latency (p50)
- β 2.61 ms p99 latency
- β³ Windjammer validation in progress (target: β₯ 95% of Rust = β₯110k req/s)
Microbenchmarks (Rust):
- JSON: 135-291 ns
- JWT: 1-2 Β΅s
- bcrypt: 254 ms
v0.17.0 Goals:
- Prove Windjammer β₯ 95% of Rust performance
- Reduce LOC gap from 11% to β€ 5% via compiler optimizations
See: examples/taskflow/ for complete details and benchmarks.
Philosophy
Write Simple, Run Fast - Ergonomic syntax that transpiles to safe, efficient Rust code.
Windjammer takes the best ideas from modern languages:
- Go: Simple concurrency (
gokeyword, channels) - Ruby: String interpolation, expressive syntax
- Elixir: Pipe operator for data transformations
- Python: Clean decorators
- Rust: Safety, performance, powerful type system
The 80/20 Rule: Windjammer provides 80% of Rust's power (memory safety, zero-cost abstractions, performance) while eliminating 80% of the complexity (manual lifetime annotations, explicit borrowing, verbose syntax).
Key Features
β¨ Automatic Trait Bound Inference π v0.10.0
No more explicit trait bounds! The compiler infers them from usage.
// Write this:
fn print<T>(x: T) {
println!("{}", x) // Compiler infers T: Display
}
// Get this (automatically):
fn print<T: Display>(x: T) { ... }
Supported inference:
Displayfromprintln!("{}", x)Clonefromx.clone()Add,Sub,Mul,Divfrom operatorsPartialEq,PartialOrdfrom comparisonsIntoIteratorfromforloops- Automatic trait imports!
π― Automatic Ownership Inference
No need to think about borrowing in most cases - the compiler figures it out.
π¨ Enhanced Decorators π v0.10.0
Clean, intuitive syntax for tests, async, and more.
@test
fn test_addition() {
assert_eq!(add(2, 2), 4)
}
@async
fn fetch_data() -> string {
// async function
}
@derive(Clone, Debug, PartialEq)
struct Point { x: int, y: int }
π¦ Named Bound Sets π v0.11.0
Reusable trait bound combinations for cleaner generic code.
// Define once:
bound Printable = Display + Debug
bound Copyable = Clone + Copy
// Use everywhere:
fn process<T: Printable + Copyable>(value: T) { ... }
π οΈ Expanded Standard Library π v0.11.0
Batteries included for common tasks:
use std.env
use std.process
use std.random
// Environment variables
let path = env.get_or("PATH", "/usr/bin")
// Process execution
let output = process.run("ls -la")?
// Random generation
let dice = random.range(1, 6)
β‘ Go-style Concurrency
Familiar go keyword and channels with Go's <- operator, but with Rust's safety guarantees.
π‘οΈ Rust's Safety & Performance
Zero-cost abstractions, memory safety, and blazing speed.
π Modern Language Features
- Generic types:
Vec<T>,Option<T>,Result<T, E>with type parameters - Trait bounds:
fn print<T: Display>(x: T),T: Display + Clonefor flexible constraints π v0.8.0 - Where clauses: Multi-line constraints for complex generic functions π v0.8.0
fn process<T, U>(a: T, b: U) where T: Display + Clone, U: Debug { ... } - Associated types: Trait-level type declarations for flexible APIs π v0.8.0
trait Container { type Item; fn get(&self) -> Self::Item; } - Trait objects: Runtime polymorphism with
dyn Traitπ v0.8.0fn render(shape: &dyn Drawable) { shape.draw() } fn create() -> dyn Shape { Circle { radius: 10 } } - Supertraits: Trait inheritance for requirement hierarchies π v0.8.0
trait Pet: Animal { fn play(&self); } trait Manager: Worker + Clone { fn manage(&self); } - Generic traits: Traits with type parameters π v0.8.0
trait From<T> { fn from(value: T) -> Self; } trait Converter<Input, Output> { fn convert(&self, input: Input) -> Output; } - Turbofish syntax:
identity::<int>(42),parse::<float>()for explicit types β¨ - Pattern matching with guards and tuple patterns
- Closures:
|x| x * 2 - Range expressions:
0..10and0..=10 - Struct shorthand:
User { name, age } - Method syntax:
implblocks with&selfand&mut self - String interpolation:
"Hello, ${name}!"β¨ - Pipe operator:
value |> func1 |> func2β¨ - Ternary operator:
condition ? true_val : false_val⨠- Labeled arguments:
create_user(name: "Alice", age: 30)β¨ - Pattern matching in function parameters:
fn process((x, y): (int, int))β¨ - Smart @auto derive: Zero-config trait inference (
@auto) β¨ - Trait system: Full trait definitions and implementations β¨
- Module system: Import and use standard library modules with aliases β¨
- Error mapping: Friendly error messages in Windjammer terms π―
π "Batteries Included" Standard Library π v0.15.0: Server-Side Complete!
Windjammer provides a comprehensive standard library that abstracts over best-in-class Rust crates with clean, Windjammer-native APIs. All stdlib modules properly abstract their implementations - you write pure Windjammer code!
What's New in v0.15.0: π Complete web development stack!
- β
HTTP Server - Build web services with
http.serve()and routing - β
File System - Full file I/O with
std.fs - β
Logging - Production-ready logging with
std.log - β
Regex - Pattern matching with
std.regex - β
CLI Parsing - Argument parsing with
std.cli
Why Proper Abstractions Matter:
- API Stability - Windjammer controls the contract, not external crates
- Future Flexibility - Can swap implementations without breaking your code
- True 80/20 - Simple APIs for 80% of use cases
- No Crate Leakage - Never see
reqwest::,axum::, orclap::in your code
Complete Modules (v0.15.0):
Web Development:
std.http- HTTP client + server (wraps reqwest + axum) β Complete Stackstd.json- JSON parsing and serialization (wraps serde_json)
File System & I/O:
std.fs- File operations, directories, metadata (Rust stdlib) π v0.15.0std.log- Logging with multiple levels (wraps env_logger) π v0.15.0
Data & Patterns:
std.regex- Regular expressions (wraps regex) π v0.15.0std.db- Database access (wraps sqlx)std.time- Date/time utilities (wraps chrono)std.crypto- Cryptography (wraps sha2, bcrypt, base64)std.random- Random generation (wraps rand)
Developer Tools:
std.cli- CLI argument parsing (wraps clap) π v0.15.0std.testing- Testing framework with assertionsstd.collections- HashMap, HashSet, BTreeMap, BTreeSet, VecDeque
System:
std.env- Environment variablesstd.process- Process executionstd.async- Async utilities
Utilities:
std.math- Mathematical functionsstd.strings- String manipulation
Example - Complete Web Service (v0.15.0):
use std.http
use std.json
use std.log
use std.fs
@derive(Serialize, Deserialize, Debug)
struct User {
id: int,
name: string,
email: string
}
// HTTP Server handlers
fn handle_index(req: Request) -> ServerResponse {
log.info("GET /")
ServerResponse::ok("Welcome to Windjammer API!")
}
fn handle_user(req: Request) -> ServerResponse {
let id = req.path_param("id")?
log.info_with("GET /users/:id", "id", id)
let user = User { id: 1, name: "Alice", email: "alice@example.com" }
ServerResponse::json(user)
}
@async
fn main() {
// Initialize logging
log.init_with_level("info")
// Read configuration
match fs.read_to_string("config.json") {
Ok(config) => log.info("Configuration loaded"),
Err(e) => log.warn_with("Using defaults", "error", e)
}
// Setup HTTP server with routing - NO axum:: in your code!
let router = Router::new()
.get("/", handle_index)
.get("/users/:id", handle_user)
log.info("Server starting on http://0.0.0.0:3000")
http.serve("0.0.0.0:3000", router).await
}
// NO THIS (crates leaked): β
// axum::Router::new()
// reqwest::get()
// serde_json::to_string()
// env_logger::init()
// YES THIS (clean Windjammer): β
// http.serve()
// http.get()
// json.stringify()
// log.init()
π οΈ Unified Project Management π v0.13.0-v0.14.0
Windjammer now has a unified wj CLI for streamlined development workflows, plus project scaffolding and dependency management!
Unified CLI (v0.13.0):
Project Management (v0.14.0):
# Create new project from templates
# Manage dependencies
wj.toml Configuration (v0.14.0):
[]
= "my-app"
= "0.1.0"
= "2021"
[]
# Add dependencies here - automatically generates Cargo.toml
80% Reduction in Boilerplate:
# Old way (v0.12.0):
&&
&&
# New way (v0.13.0+):
Ownership Inference Strategy
The key innovation is automatic ownership inference with these rules:
1. Smart Defaults
- Primitive types (int, float, bool): Always copied (implement Copy trait)
- String literals: Owned by default
- Struct fields: Owned by default unless marked otherwise
- Function parameters: Borrowed by default (immutable
&T) - Function returns: Owned by default
2. Mutation Detection
// Immutable borrow inferred
fn print_length(s: string) {
println!("{}", s.len())
}
// Mutable borrow inferred from assignment
fn increment(x: int) {
x = x + 1 // Assignment detected β infers &mut
}
// Mutable borrow inferred from method call
fn append_text(s: string) {
s.push_str("!") // Mutation detected β infers &mut
}
// Ownership transfer inferred from return
fn take_ownership(s: string) -> string {
s // Returned β infers owned parameter
}
3. Escape Analysis
Like Go, we analyze if values escape the function:
- Values that don't escape β borrow
- Values that escape (returned, stored) β owned
- Ambiguous cases β owned (safe default)
4. Explicit Annotations (Rare)
When inference isn't enough, use Rust-style annotations:
fn process(s: &string) -> string // Explicit borrow
fn modify(s: &mut string) // Explicit mutable borrow
fn take(s: string) -> string // Explicit ownership (inferred by default for returns)
5. Shared Ownership
When multiple owners needed:
// Automatic Rc/Arc when:
// - Value assigned to multiple variables in different scopes
// - Value stored in multiple struct fields
// - Cross-thread sharing detected β Arc
let data = shared("expensive data") // Explicit Rc/Arc
Decorators
Use @ for decorators (Python/TypeScript style):
@route("/api/users")
@auth_required
fn get_users() -> Result<Vec<User>, Error>
@timing
@cache(ttl: 60)
fn expensive_calculation(n: int) -> int
Built-in decorators:
@timing- Measure execution time@cache- Memoize function results@route(path)- HTTP routing (with web frameworks)@get,@post,@put,@delete- HTTP method routing
Concurrency
Go-style syntax with Rust safety, including Go-style channel operators:
use std.sync.mpsc
fn main()
// Traditional Rust syntax also works:
fn alternative_example()
// Async/await style also supported
async fn fetch_data(url: string) -> Result<string, Error>
Channel Operators:
channel <- valueβ Send to channel (transpiles tochannel.send(value))<-channelβ Receive from channel (transpiles tochannel.recv())
Syntax Examples
Variables
let x = 42 // Transpiles to: let x = 42;
let mut y = 10 // Transpiles to: let mut y = 10;
Functions
fn add(a: int, b: int) -> int
// Transpiles to:
// fn add(a: i32, b: i32) -> i32 { a + b }
Structs and Impl Blocks
struct User
impl User
fn main()
Struct Features:
- Shorthand field initialization:
User { name, age }when variables match field names - Self parameters:
&self,&mut self, orself(owned) - Methods and associated functions via
implblocks
Error Handling
use std.fs
use std.io
fn read_config(path: string) -> Result<string, Error>
Generic Types
// Vec<T> - Dynamic arrays
let numbers: Vec<int> = vec![1, 2, 3, 4, 5]
let names: Vec<string> = Vec.new()
// Option<T> - Optional values
fn find_user(id: int) -> Option<User>
// Result<T, E> - Error handling
fn read_file(path: string) -> Result<string, Error>
Pattern Matching
// Match as an expression
let value = Some(42)
let result = match value
// Match with guards
match (x, y)
// Match with tuple patterns
match (cell, live_neighbors)
Closures and Iterators
// Closures with Go-style syntax
let double = |x| x * 2
let add = |a, b| a + b
// Iterator methods
let numbers = vec![1, 2, 3, 4, 5]
let doubled = numbers.iter().map(|n| n * 2).collect()
let evens = numbers.iter().filter(|n| n % 2 == 0).collect()
// Range expressions
for i in 0..10
for i in 0..=10
References and Borrowing
// Create references
let x = 42
let ref_x = &x
let mut_ref_x = &mut x
// Function parameters can be explicit or inferred
fn read_value(x: &int) -> int
fn modify_value(x: &mut int)
fn consume_value(x: int)
// Or let the compiler infer!
fn inferred_borrow(x: int)
String Interpolation β¨
let name = "Alice"
let age = 30
let score = 95.5
// Clean, readable string formatting
println!("Hello, ${name}!")
println!("${name} is ${age} years old")
println!("Score: ${score * 100.0}%")
// Works with any expression
let message = "Result: ${calculate(x, y) + 10}"
Pipe Operator β¨
fn double(x: int) -> int
fn add_ten(x: int) -> int
fn to_string(x: int) -> string
// Functional composition made readable
let result = 5
|> double
|> add_ten
|> double
|> to_string
// Equivalent to: to_string(double(add_ten(double(5))))
// Result: "40"
Labeled Arguments β¨
fn create_user(name: string, age: int, email: string)
// Traditional positional arguments
create_user("Alice", 30, "alice@example.com")
// Labeled arguments for clarity (especially with many parameters)
create_user(
name: "Bob",
age: 25,
email: "bob@example.com"
)
// Mix positional and labeled
create_user("Charlie", age: 35, email: "charlie@example.com")
// Great for functions with many parameters or similar types
fn configure_server(
host: string,
port: int,
timeout: int,
max_connections: int,
enable_logging: bool
)
// Much clearer than: configure_server("localhost", 8080, 30, 100, true)
configure_server(
host: "localhost",
port: 8080,
timeout: 30,
max_connections: 100,
enable_logging: true
)
Pattern Matching in Function Parameters β¨
// Instead of manually destructuring...
fn distance_old(point: (int, int)) -> float
// Destructure directly in the parameter!
fn distance((x, y): (int, int)) -> float
// Real-world example: API response handler
fn handle_response((status, body): (int, string))
let response = (200, "Data loaded")
handle_response(response)
// Think of it as: PATTERN : TYPE
// (x, y) β pattern | (int, int) β type
@auto Derive β¨
// Automatic trait derivation - no manual impl needed!
@auto(Debug, Clone, Copy)
struct Point
@auto(Debug, Clone)
struct User
let p1 = Point
let p2 = p1 // Copy works automatically
println!("{:?}", p1) // Debug works automatically
// Equivalent to Rust's #[derive(Debug, Clone, Copy)]
// But with cleaner, more intuitive syntax!
Trait System β¨
// Define traits
trait Drawable
// Implement traits
struct Circle
impl Drawable for Circle
// Generic traits with associated types
trait Iterator<Item>
impl Iterator<int> for Counter
Generic Trait Implementations β¨
// Implement generic traits with concrete types
trait From<T>
impl From<int> for String
// Multiple type parameters
trait Converter<Input, Output>
impl Converter<int, string> for IntToString
Generic Enums β¨
// Define generic enums
enum Option<T>
enum Result<T, E>
// Use with pattern matching
fn safe_divide(a: int, b: int) -> Result<int, string>
fn main()
Type Mappings
| Windjammer | Rust |
|---|---|
| int | i64 |
| int32 | i32 |
| uint | u64 |
| float | f64 |
| bool | bool |
| string | String (owned) or &str (borrowed) |
| Vec<T> | Vec<T> |
| Option<T> | Option<T> |
| Result<T,E> | Result<T,E> |
| &T | &T (immutable reference) |
| &mut T | &mut T (mutable reference) |
Quick Start
Installation
Windjammer is easy to install with multiple options for all platforms:
Quick Install
macOS / Linux:
# Using Homebrew (recommended)
# Or using Cargo
Windows:
# Using Scoop (recommended)
scoop bucket add windjammer https://github.com/jeffreyfriedman/scoop-windjammer
scoop install windjammer
# Or using Cargo
cargo install windjammer
All Installation Methods
| Method | Command | Best For |
|---|---|---|
| Homebrew (macOS/Linux) | brew install windjammer |
Mac/Linux users |
| Cargo (All platforms) | cargo install windjammer |
Rust developers |
| Docker | docker pull ghcr.io/jeffreyfriedman/windjammer |
Container workflows |
| Pre-built Binaries | Download from Releases | Quick setup |
| Build from Source | git clone ... && ./install.sh |
Contributors |
| Snap (Linux) | snap install windjammer --classic |
Ubuntu/Linux |
| Scoop (Windows) | scoop install windjammer |
Windows users |
π Full installation guide: docs/INSTALLATION.md
Verify Installation
Your First Program
Create hello.wj:
fn main() {
let name = "Windjammer"
println!("Hello, {}!", name)
}
Transpile and run:
Examples
See the examples/ directory for complete working examples:
Language Basics:
- Basic Features - Variables, functions, control flow
- Structs & Methods - Data structures and impl blocks
- Enums & Matching - Enumerations and pattern matching
- Traits - Trait definitions and implementations
- Modern Features - String interpolation, pipe operator, ternary
Standard Library: 6. Module System - Module imports and usage 7. File Operations - Using std.fs for file I/O 8. Core Language - Basic language test
Advanced Examples: 9. WASM Hello - WebAssembly "Hello World" 10. WASM Game - Conway's Game of Life in the browser
Development Tools
Language Server
Windjammer includes a high-performance language server built with Salsa for incremental compilation:
- β‘ Fast: Only recomputes what changed
- π IntelliSense: Auto-completion, hover info, diagnostics
- π― Ownership Hints: See inferred borrowing inline
- π Instant Feedback: Real-time error checking
Install: cargo install --path crates/windjammer-lsp
VSCode Extension
Features:
- Syntax highlighting
- Auto-completion
- Error diagnostics
- Code navigation
- Ownership inference hints
Install from editors/vscode/ or search "Windjammer" in the marketplace (coming soon).
Build & Run
# Transpile .wj files to .rs
# Or specify files
# Check for errors without generating code
# Run the generated Rust code
When to Use Windjammer
β Choose Windjammer For
- Web APIs & Services - Built-in HTTP, JSON, ergonomic syntax
- CLI Tools - Fast development with system-level performance
- Data Processing - Pipe operator for clean transformations
- Microservices - Fast, safe, memory-efficient
- Learning Systems Programming - Gentler curve than Rust
- Teams Transitioning from Go - Familiar syntax, better performance
- 80% of Use Cases - Most applications don't need Rust's full complexity
β οΈ Consider Rust Instead For
- Operating Systems - Need maximum low-level control
- Embedded Systems - Need
no_stdand precise memory management - Game Engines - Need every manual optimization
- The Critical 20% - When you truly need Rust's full power
β οΈ Consider Go Instead For
- Dead-Simple Services - No performance requirements
- Rapid Prototypes - Speed over safety
- Teams Unfamiliar with Systems - Easiest learning curve
π See COMPARISON.md for detailed analysis
π Documentation
For Users:
- π GUIDE.md - Complete developer guide (Rust book style)
- π COMPARISON.md - Windjammer vs Rust vs Go (honest tradeoffs)
- π― README.md - This file (quick start and overview)
For Contributors:
- π PROGRESS.md - Current status and next steps
- πΊοΈ ROADMAP.md - Development phases and timeline
- π¨ Traits Design - Ergonomic trait system design
- π§ Auto-Reference Design - Automatic reference insertion
- π Error Mapping Design - RustβWindjammer error translation
Standard Library:
- π std/README.md - Philosophy and architecture
- π¦ std/*/API.md - Module specifications (fs, http, json, testing)
Rust Interoperability
β YES: 100% Rust Crate Compatibility!
Windjammer transpiles to Rust, giving you:
- β ALL Rust crates work - Tokio, Serde, Actix, Reqwest, etc.
- β No FFI needed - It IS Rust under the hood
- β Same performance - Zero overhead translation
- β Mix .wj and .rs files - Use both in same project
- β Call Rust from Windjammer - And vice versa
Example:
// Your Windjammer code
use serde.json
use tokio.time
@auto(Serialize, Deserialize)
struct Config {
timeout: int,
}
// Uses Rust crates directly!
async fn load_config() -> Result<Config, Error> {
let text = fs.read_to_string("config.json")?
let config = serde_json::from_str(&text)?
Ok(config)
}
Transpiles to idiomatic Rust:
use ;
use time;
async
β‘ Performance
Windjammer is blazingly fast for development iteration:
Compilation Speed
- Simple program (10 lines): ~8Β΅s
- Medium program (30 lines): ~25Β΅s
- Complex program (50 lines): ~60Β΅s
17,000x faster than rustc for the transpilation step!
Runtime Performance
Since Windjammer transpiles to Rust, runtime performance is identical to hand-written Rust:
- β Zero-cost abstractions
- β No runtime overhead
- β Same binary size
- β Same memory usage
Why So Fast?
- No LLVM: Generates Rust source instead of machine code
- Incremental: Only transpiles changed
.wjfiles - Simple AST: Go-inspired syntax is easier to parse
- No borrow checking: Rust handles that in pass 2
See BENCHMARKS.md for detailed performance analysis.
π License
Windjammer is dual-licensed under either:
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
This means you can choose either license when using Windjammer.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Windjammer by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.