Examples
Copy-paste programs showcasing structs, enums, generics, FFI, error handling, and more.
All examples below compile as-is against Turf v1.0.0. Save any of them to a .tr file, then turf file.tr -o file && ./file.
Structs, constructors, instance methods, and static methods
extern fn strlen(s: string): int;
struct User { age: int, name: string }
fn User.new(age: int, name: string): void { self.age = age; self.name = name; }
fn User.grow(): void { self.age = self.age + 1; }
fn User.rename(new_name: string): void { self.name = new_name; }
fn User.describe() static: string { return "a user"; }
fn main(): int {
mut u: User = User::new(0, "unnamed");
u.grow();
assert(u.age == 1, "");
u.rename("Bob");
assert(User::describe() == "a user", "");
return 0;
}
Enums and modules
import io;
enum Status { Pending, Active, Closed }
fn describe(s: Status): string {
compare s {
matches Status::Pending:
return "pending";
done
matches Status::Active:
return "active";
done
otherwise:
return "closed";
}
}
fn main(): int {
immut s: Status = Status::Active;
io::printline(describe(s));
assert(Status::COUNT == 3, "");
return 0;
}
Arrays of structs
extern fn strlen(s: string): int;
struct User {
age: int,
name: string
}
fn User.new(age: int, name: string): void {
self.age = age;
self.name = name;
}
fn main(): int {
mut users: User[5] = [
User::default(),
User::default(),
User::default(),
User::default(),
User::default()
];
users[0] = User::new(25, "Alice");
users[1] = User::new(30, "Bob");
users[2] = User::new(35, "Charlie");
assert(users[0].age == 25, "");
assert(strlen(users[0].name) == 5, "");
assert(users[1].age == 30, "");
assert(strlen(users[1].name) == 3, "");
assert(users[2].age == 35, "");
assert(strlen(users[2].name) == 7, "");
return 0;
}
Casting and type conversion
fn main(): int {
mut a: double = 42 to double;
assert(a > 41.9 && a < 42.1, "");
mut b: int = 3.75 to int;
assert(b == 3, ""); // truncates the decimal part
mut c: int = "100" to int;
assert(c == 100, "");
mut x: int = 10;
mut s9: string = x to string;
return 0;
}
Loops, break, continue, range-for
fn main(): int {
mut i: int = 0;
mut sum: int = 0;
while i < 10 {
i = i + 1;
if i % 2 == 0 {
continue;
}
sum = sum + i;
}
assert(sum == 25, "");
mut for_sum: int = 0;
for j in 1..10 step j += 1 {
if j % 2 == 0 {
continue;
}
for_sum = for_sum + j;
}
assert(for_sum == 25, "");
return 0;
}
Error handling with recover
import io;
error MathError {
DivisionByZero
}
fn divide(a: int, b: int): !int {
if b == 0 {
return MathError::DivisionByZero;
}
return a / b;
}
fn tryDivide(a: int, b: int): int {
return divide(a, b) recover as err run {
if err == MathError::DivisionByZero {
io::printline("division by zero");
}
return -1;
};
}
fn main(): int {
mut x: int = divide(10, 0) recover produce 0;
assert(x == 0, "");
assert(tryDivide(10, 0) == -1, "");
assert(tryDivide(10, 2) == 5, "");
return 0;
}
Generics: a user-defined Box<T> and the stdlib’s List<T>
import io;
import list::List;
struct Box<T> {
val: T
}
fn Box.new(v: T): void {
self.val = v;
}
fn Box.get(): T {
return self.val;
}
fn main(): int {
mut b: Box<int> = Box::new(42);
assert(b.get() == 42, "");
mut nums: List<int> = List::default();
nums.push(10);
nums.push(20);
assert(nums.length() == 2, "");
return 0;
}
State machines
import io;
machine TrafficLight {
Red -> Green,
Green -> Yellow,
Yellow -> Red
}
fn main(): int {
mut light: TrafficLight = TrafficLight::Red;
compare light {
matches TrafficLight::Red:
light.transition(TrafficLight::Green); // compile-time-proven safe
done
otherwise:
io::printline("not red");
}
assert(light == TrafficLight::Green, "");
return 0;
}
FFI — pointers and memory
extern fn malloc(size: int): ptr;
extern fn free(p: ptr): void;
extern fn memset(p: ptr, c: int, n: int): ptr;
extern fn memcpy(dst: ptr, src: ptr, n: int): ptr;
extern fn strlen(s: string): int;
// An ordinary function may never take or return a raw `ptr`/`T*` (even
// inside `unsafe { }`) -- only `extern fn` bindings and lib/std can, so
// buffer allocation stays inlined in main() below instead of its own helper.
fn main(): int {
unsafe {
mut b: ptr = malloc(32);
memset(b, 0, 32);
free(b);
}
mut len: int = strlen("verify");
assert(len == 6, "");
return 0;
}
A larger FFI showcase — file I/O, libm, environment variables, sockets, variadic printf via extern fn printf(fmt: string, ...): int;, and linking against arbitrary system libraries via extern from "libname" fn — lives in the test suite alongside the rest of the examples above.
Real-world-shaped programs
The showcase/ directory has larger programs combining multiple stdlib modules — no extern fn/ptr in the showcase files themselves:
http_server.tr/http_client.tr— a full HTTP request/response round trip over a real TCP socket, both ends written in Turf.kv_store_server.tr/kv_store_client.tr— a key-value store client/server pair.llvm_ffi_selfhost_demo.tr— a self-hosting-adjacent LLVM-C FFI demo.text_toolkit.tr— exercisesstrings/fs/Set/sort-and-search/time.config_and_dice.tr— a JSON-config-driven dice roller exercisingjson/random/net::resolve_hostname.
See that directory’s own files for details on running each one.