Expressive and clear syntax
Forward pipes (|>), immutable by default.
Default & Keyword arguments. "?"/Rust like error handling.
Traits, generics, no null.
A Rust-flavoured language with real goroutines and a Swift-like memory model - run it like a script, or ship it as a single binary.
Get started → Take a Tour Playground GitHub
Open source · Apache-2.0 · pre-1.0
Forward pipes (|>), immutable by default.
Default & Keyword arguments. "?"/Rust like error handling.
Traits, generics, no null.
Deterministic reference counting - closely modeled on
Swift's ARC, with automatic cycle collection added - plus
arena { } regions reclaim memory as it goes out
of scope. No borrow checker, no lifetimes, no tracing collector.
cohort blocks with spawn for structured
concurrency by default. go and typed channels on
an M:N scheduler. Blocking calls park the goroutine, not the thread.
A bytecode VM with JIT and a REPL for fast iteration; a single, dependency-free native binary via LLVM when you ship.
Result / Option,
exhaustive match.
A broad standard library - HTTP, JSON, crypto, SQL, compression, and more - and a clean path to drop down into safe synchronous Rust when you need it.
Hit Run on any sample - it executes right in your browser, no install. Gossamer's VM is compiled to WebAssembly.
fn double(x: i64) -> i64 { x * 2 }
fn add(a: i64, b: i64) -> i64 { a + b }
fn clamp(lo: i64, hi: i64, x: i64) -> i64 {
if x < lo { lo } else if x > hi { hi } else { x }
}
let n = 3 |> double |> |v| add(10, v) |> |v| clamp(0, 100, v)
println!("answer: {}", n)
use std::http::router
// A request router - the heart of a web service. Register the route
// table once (note the {id} path parameter), then match each request.
let routes = router::new()
let _ = router::add(routes, "GET", "/")
let _ = router::add(routes, "GET", "/users/{id}")
let _ = router::add(routes, "POST", "/users")
let requests = #[("GET", "/"), ("GET", "/users/42"), ("POST", "/users"), ("DELETE", "/users/42")]
for (method, path) in requests {
let status = match router::lookup(routes, method, path) {
Some(_) => "200 ok",
None => "404 not found",
}
println!("{} {} -> {}", method, path, status)
}
fn fib(n: i64) -> i64 {
if n < 2 { n } else { fib(n - 1) + fib(n - 2) }
}
fn main() {
// spawn runs fib on a goroutine; join collects its result.
let h = spawn(|| fib(30))
match h.join() {
Ok(v) => println!("fib(30) on a goroutine = {}", v),
Err(e) => eprintln!("worker failed: {}", e),
}
}
enum Shape {
Circle(f64),
Rect { w: f64, h: f64 },
Triangle(f64, f64),
}
fn area(s: &Shape) -> f64 {
match s {
Shape::Circle(r) => 3.14159 * r * r,
Shape::Rect { w, h } => *w * *h,
Shape::Triangle(b, h) => 0.5 * b * h,
}
}
// Top-level statements - no fn main() needed
let shapes = #[Shape::Circle(3.0), Shape::Rect { w: 4.0, h: 5.0 }, Shape::Triangle(6.0, 2.0)]
for s in shapes {
println!("area = {:.2}", area(&s))
}
use std::collections::{BTreeSet, Map, Set, Deque, Queue, Stack, MaxHeap, MinHeap}
let mut nums = #[]
nums.push(10)
nums.push(20)
let dropped = nums.remove(0).unwrap_or(-1)
println!("[] Vec: len={} removed={} first={}", nums.len(), dropped, nums[0])
let fixed = [1, 2, 3]
println!("[] fixed array: len={}", fixed.len())
let mut scores: Map<String, i64> = {}
scores.insert("ada", 100)
scores.insert("grace", 95)
let old_score = scores.remove("ada").unwrap_or(0)
println!("{} Map: len={} removed={} has_grace={}",
"{}", scores.len(), old_score, scores.contains_key("grace"))
let mut seen = #{}
seen.insert(3)
seen.insert(5)
let removed_seen = seen.remove(3)
println!("#{} Set: len={} removed={} has5={}",
"{}", seen.len(), removed_seen, seen.contains(5))
let mut ordered: BTreeSet<i64> = #{}
ordered.insert(4)
ordered.insert(1)
let removed_ordered = ordered.remove(4)
println!("#{} BTreeSet: len={} removed={} values={}",
"{}", ordered.len(), removed_ordered, ordered.to_vec().join(","))
let mut max_heap = MaxHeap::new()
max_heap.push(5)
max_heap.push(9)
let largest = max_heap.pop().unwrap_or(0)
println!("MaxHeap: len={} removed={}", max_heap.len(), largest)
let mut min_heap = MinHeap::new()
min_heap.push(5)
min_heap.push(2)
let smallest = min_heap.pop().unwrap_or(0)
println!("MinHeap: len={} removed={}", min_heap.len(), smallest)
let mut deque = Deque::new()
deque.push_front(2)
deque.push_back(3)
let front = deque.pop_front().unwrap_or(0)
let back = deque.pop_back().unwrap_or(0)
println!("Deque: front={} back={} len={}", front, back, deque.len())
let mut queue = Queue::from([7, 8])
queue.push(9)
let next = queue.pop().unwrap_or(0)
println!("Queue: next={} len={}", next, queue.len())
let mut stack = Stack::from([7, 8])
stack.push(9)
let top = stack.pop().unwrap_or(0)
println!("Stack: top={} len={}", top, stack.len())
let entry = (1, "widgets", 2.5)
let (id, name, unit_price) = entry
println!("Tuple: {} {} {:.2} (first={})", id, name, unit_price, entry.0)
Short, focused guides that map what you already know onto Gossamer.
Write a .gos file and run it with the
gos toolchain - no build step needed while
you iterate:
$ gos run hello.gos
hello, gossamer
$ gos build --release hello.gos # one native binary, ready to ship
Runs on Linux (x86_64, aarch64, armv7), macOS (Intel & Apple Silicon), and Windows (x86_64).