Examples
Learn FezLang by reading real code. Each example is 30–100 lines — long enough to be real, short enough to read in 2 minutes.
01. Hello World
The simplest FezLang program. Print a message, declare a variable, use string interpolation.
io · variables · string interpolation
// Hello World in FezLang
io.print("hello, world!")
name = "FezLang"
version = 1
io.print("Welcome to {name} v{version}")
02. Calculator
A simple REPL calculator that reads user input, parses it, and performs basic math.
io · math · if/else · string interpolation
import "math"
io.print("Simple Calculator")
io.print("Enter: number operator number")
io.print("Operators: + - * /")
while true {
input = io.read("> ")
parts = str.split(input, " ")
if str.len(parts) != 3 {
io.print("Usage: 5 + 3")
continue
}
a = math.parse_f64(parts[0])
op = parts[1]
b = math.parse_f64(parts[2])
if op == "+" { io.print("= {a + b}") }
else if op == "-" { io.print("= {a - b}") }
else if op == "*" { io.print("= {a * b}") }
else if op == "/" {
if b == 0.0 {
io.print("Error: division by zero")
} else {
io.print("= {a / b}")
}
} else {
io.print("Unknown operator: {op}")
}
}
03. TODO List
A CLI task manager with add, remove, and list commands. Shows structs, modules, and a REPL loop.
structs · modules · arrays · while loop · io
struct Task {
id: int
text: str
done: bool
}
module todo {
next_id = 1
tasks = []
fn add(text: str) -> Task {
task = Task { id: next_id, text: text, done: false }
tasks = append(tasks, task)
next_id = next_id + 1
return task
}
fn remove(id: int) -> bool {
for i, task in tasks {
if task.id == id {
tasks = splice(tasks, i, 1)
return true
}
}
return false
}
fn list() {
if len(tasks) == 0 {
io.print(" No tasks.")
return
}
for task in tasks {
mark = if task.done { "x" } else { " " }
io.print(" [{mark}] {task.id}: {task.text}")
}
}
}
io.print("TODO List — commands: add , done , remove , list, quit")
while true {
input = io.read("> ")
parts = str.split(input, " ")
cmd = parts[0]
if cmd == "quit" { break }
else if cmd == "list" { todo.list() }
else if cmd == "add" {
text = str.join(parts[1:], " ")
task = todo.add(text)
io.print(" Added: {task.text} (#{task.id})")
} else if cmd == "remove" {
id = math.parse_int(parts[1])
todo.remove(id)
} else {
io.print(" Unknown command: {cmd}")
}
}
04. FizzBuzz
The classic interview question. Clean, readable, no tricks.
for loop · modulo · if/else · io
// FizzBuzz: print 1-100
// multiples of 3 → "Fizz"
// multiples of 5 → "Buzz"
// multiples of both → "FizzBuzz"
for i in 1..101 {
if i % 15 == 0 {
io.print("FizzBuzz")
} else if i % 3 == 0 {
io.print("Fizz")
} else if i % 5 == 0 {
io.print("Buzz")
} else {
io.print("{i}")
}
}
05. File Processor
Read a CSV file, process each line, and write results. Shows file I/O and error handling.
file · str · error handling · for loop
import "file"
// Read input CSV
lines, err = file.read_lines("scores.csv")
if err {
io.print("Error reading file: {err.message}")
os.exit(1)
}
results = []
for line in lines {
cols = str.split(line, ",")
if len(cols) < 2 { continue }
name = str.trim(cols[0])
score = math.parse_int(str.trim(cols[1]))
grade = if score >= 90 { "A" }
else if score >= 80 { "B" }
else if score >= 70 { "C" }
else { "F" }
results = append(results, "{name},{score},{grade}")
}
// Write output
output = str.join(results, "\n")
err = file.write("grades.csv", output)
if err {
io.print("Error writing file: {err.message}")
os.exit(1)
}
io.print("Processed {len(results)} records → grades.csv")
06. JSON API Client
Fetch data from a JSON API, parse the response, and display results.
http · json · error handling · structs
import "http"
import "json"
struct Post {
id: int
title: str
body: str
}
// Fetch posts from API
resp, err = http.get("https://jsonplaceholder.typicode.com/posts")
if err {
io.print("Request failed: {err.message}")
os.exit(1)
}
posts, err = json.decode(resp.body, []Post)
if err {
io.print("Parse error: {err.message}")
os.exit(1)
}
// Display first 5 posts
for post in posts[:5] {
io.print("#{post.id}: {post.title}")
io.print(" {str.slice(post.body, 0, 80)}...")
io.print("")
}
07. HTTP Server
A simple JSON API server with routes, request handling, and JSON responses.
http · json · modules · structs · routing
import "http"
import "json"
struct Message {
text: str
status: int
}
module api {
fn hello(req: http.Request) -> http.Response {
name = req.query("name")
if name == "" { name = "world" }
msg = Message { text: "hello, {name}!", status: 200 }
return http.json_response(200, json.encode(msg))
}
fn health(req: http.Request) -> http.Response {
return http.json_response(200, `{"status": "ok"}`)
}
fn not_found(req: http.Request) -> http.Response {
msg = Message { text: "not found", status: 404 }
return http.json_response(404, json.encode(msg))
}
}
server = http.new_server()
server.route("GET", "/hello", api.hello)
server.route("GET", "/health", api.health)
server.fallback(api.not_found)
io.print("Server listening on :8080")
server.listen(":8080")
08. Error Handling
Multiple returns, error propagation, defer for cleanup, and the _ discard pattern.
error handling · multiple returns · defer · _ discard
import "file"
import "json"
struct Config {
host: str
port: int
debug: bool
}
module config {
fn load(path: str) -> Config, err {
// Read file — propagate error if it fails
data, err = file.read(path)
if err {
return Config{}, error("failed to read config: {err.message}")
}
// Parse JSON — propagate error if it fails
cfg, err = json.decode(data, Config)
if err {
return Config{}, error("failed to parse config: {err.message}")
}
// Validate
if cfg.port < 1 {
return Config{}, error("invalid port: {cfg.port}")
}
return cfg, nil
}
}
// Load config — handle the error
cfg, err = config.load("app.json")
if err {
io.print("Config error: {err.message}")
io.print("Using defaults...")
cfg = Config { host: "localhost", port: 8080, debug: false }
}
io.print("Server: {cfg.host}:{cfg.port}")
io.print("Debug: {cfg.debug}")
// Sometimes you don't care about the error
_ = file.write("last_run.txt", time.now())
// Defer runs cleanup in reverse order
fn process_file(path: str) -> err {
f, err = file.open(path)
if err { return err }
defer file.close(f)
lock, err = file.lock(path)
if err { return err }
defer file.unlock(lock)
// Work with file — both close and unlock
// happen automatically when function returns
data = file.read_all(f)
io.print("Read {str.len(data)} bytes")
return nil
}
09. Concurrency
Spawn goroutine-like tasks, communicate via channels, and wait for results.
spawn · channel · concurrency · http
import "http"
import "time"
struct Result {
url: str
status: int
elapsed: f64
}
fn fetch(url: str, ch: channel) {
start = time.now_ms()
resp, err = http.get(url)
elapsed = time.now_ms() - start
if err {
ch <- Result { url: url, status: 0, elapsed: elapsed }
} else {
ch <- Result { url: url, status: resp.status, elapsed: elapsed }
}
}
urls = [
"https://fezlang.org",
"https://go.dev",
"https://rust-lang.org",
"https://python.org",
"https://nodejs.org",
]
ch = channel(len(urls))
for url in urls {
spawn fetch(url, ch)
}
// Collect results
for _ in urls {
result = <-ch
status = if result.status == 0 { "FAIL" } else { "{result.status}" }
io.print("{result.url} → {status} ({result.elapsed}ms)")
}
10. Closures
Higher-order functions, function factories, and callbacks. Functions are first-class values.
closures · lambdas · higher-order functions · first-class functions
// Function factory — returns a function
fn make_adder(x: int) -> fn(int) -> int {
return |y| x + y
}
add5 = make_adder(5)
add10 = make_adder(10)
io.print("add5(3) = {add5(3)}") // 8
io.print("add10(3) = {add10(3)}") // 13
// Map with lambda
numbers = [1, 2, 3, 4, 5]
doubled = map(numbers, |n| n * 2)
io.print("doubled: {doubled}") // [2, 4, 6, 8, 10]
// Filter with lambda
evens = filter(numbers, |n| n % 2 == 0)
io.print("evens: {evens}") // [2, 4]
// Reduce
sum = reduce(numbers, 0, |acc, n| acc + n)
io.print("sum: {sum}") // 15
// Compose functions
fn compose(f: fn(int) -> int, g: fn(int) -> int) -> fn(int) -> int {
return |x| f(g(x))
}
double = |x| x * 2
increment = |x| x + 1
double_then_inc = compose(increment, double)
io.print("double_then_inc(5) = {double_then_inc(5)}") // 11
11. Enums & Structs
Define enums and structs, use them together in a realistic order processing module.
enum · struct · modules · pattern matching
enum Status {
Pending
Processing
Shipped
Delivered
Cancelled
}
struct Item {
name: str
price: f64
qty: int
}
struct Order {
id: int
items: []Item
status: Status
}
module orders {
fn total(order: Order) -> f64 {
sum = 0.0
for item in order.items {
sum = sum + item.price * item.qty
}
return sum
}
fn status_label(s: Status) -> str {
if s == Status.Pending { return "Pending" }
if s == Status.Processing { return "Processing" }
if s == Status.Shipped { return "Shipped" }
if s == Status.Delivered { return "Delivered" }
return "Cancelled"
}
fn summary(order: Order) {
io.print("Order #{order.id} — {orders.status_label(order.status)}")
for item in order.items {
io.print(" {item.name} x{item.qty} @ ${item.price}")
}
io.print(" Total: ${orders.total(order)}")
}
}
order = Order {
id: 1042,
items: [
Item { name: "Keyboard", price: 79.99, qty: 1 },
Item { name: "USB Cable", price: 9.99, qty: 3 },
],
status: Status.Shipped,
}
orders.summary(order)
12. Modules Demo
Nested modules, dot-path access, and how FezLang organizes code without classes or packages.
modules · nesting · dot access · organization
// Modules nest. The dot is always a path.
module math {
const PI = 3.14159265
module trig {
fn sin(x: f64) -> f64 {
// Taylor series approximation
result = x
term = x
for i in 1..10 {
term = term * (-1.0) * x * x / ((2 * i) * (2 * i + 1))
result = result + term
}
return result
}
fn cos(x: f64) -> f64 {
return trig.sin(math.PI / 2.0 - x)
}
}
module convert {
fn deg_to_rad(deg: f64) -> f64 {
return deg * math.PI / 180.0
}
fn rad_to_deg(rad: f64) -> f64 {
return rad * 180.0 / math.PI
}
}
}
// Clear, unambiguous paths
angle = math.convert.deg_to_rad(45.0)
result = math.trig.sin(angle)
io.print("sin(45°) = {result}")
// Every dot is a path into a module or struct
// Never a method call. Never a dispatch.
io.print("π = {math.PI}")
io.print("90° = {math.convert.deg_to_rad(90.0)} rad")
13. Ref Parameters
Pass by value is the default. Use ref when you need to mutate in place — explicit at both sites.
ref · pass by value · mutation · structs
struct Point {
x: f64
y: f64
}
// Pass by value — original is NOT modified
fn translate_copy(p: Point, dx: f64, dy: f64) -> Point {
return Point { x: p.x + dx, y: p.y + dy }
}
// Pass by ref — original IS modified
fn translate(p: ref Point, dx: f64, dy: f64) {
p.x = p.x + dx
p.y = p.y + dy
}
origin = Point { x: 0.0, y: 0.0 }
// Value: origin unchanged
moved = translate_copy(origin, 5.0, 3.0)
io.print("origin: ({origin.x}, {origin.y})") // (0, 0)
io.print("moved: ({moved.x}, {moved.y})") // (5, 3)
// Ref: origin IS changed — explicit at call site
translate(ref origin, 10.0, 20.0)
io.print("origin: ({origin.x}, {origin.y})") // (10, 20)
// The ref keyword is required at BOTH sites:
// - fn declaration: p: ref Point
// - call site: translate(ref origin, ...)
// This makes mutation always visible to the reader.
14. SQLite CRUD
Connect to a database, create a table, and perform full CRUD operations.
db · error handling · structs · modules · CRUD
import "db"
struct User {
id: int
name: str
email: str
}
module users {
fn init(conn: db.Conn) -> err {
return db.execute(conn, `
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)
`)
}
fn create(conn: db.Conn, name: str, email: str) -> User, err {
err = db.execute(conn, "INSERT INTO users (name, email) VALUES (?, ?)", name, email)
if err { return User{}, err }
row, err = db.query_one(conn, "SELECT id, name, email FROM users WHERE email = ?", email)
if err { return User{}, err }
return User { id: row.int("id"), name: row.str("name"), email: row.str("email") }, nil
}
fn find(conn: db.Conn, id: int) -> User, err {
row, err = db.query_one(conn, "SELECT id, name, email FROM users WHERE id = ?", id)
if err { return User{}, err }
return User { id: row.int("id"), name: row.str("name"), email: row.str("email") }, nil
}
fn update(conn: db.Conn, id: int, name: str) -> err {
return db.execute(conn, "UPDATE users SET name = ? WHERE id = ?", name, id)
}
fn delete(conn: db.Conn, id: int) -> err {
return db.execute(conn, "DELETE FROM users WHERE id = ?", id)
}
fn all(conn: db.Conn) -> []User, err {
rows, err = db.query(conn, "SELECT id, name, email FROM users ORDER BY id")
if err { return [], err }
result = []
for row in rows {
result = append(result, User { id: row.int("id"), name: row.str("name"), email: row.str("email") })
}
return result, nil
}
}
conn, err = db.connect("sqlite:app.db")
if err { io.print("DB error: {err.message}"); os.exit(1) }
defer db.close(conn)
users.init(conn)
user, _ = users.create(conn, "Cal", "cal@fez.dev")
io.print("Created: {user.name} (#{user.id})")
users.update(conn, user.id, "Calvin")
user, _ = users.find(conn, user.id)
io.print("Updated: {user.name}")
all, _ = users.all(conn)
for u in all {
io.print(" #{u.id} {u.name} <{u.email}>")
}
15. TCP Echo Server
A concurrent TCP server that echoes back anything a client sends. One spawn per connection.
net · spawn · concurrency · error handling · defer
import "net"
fn handle_client(conn: net.Conn) {
defer net.tcp_close(conn)
addr = net.remote_addr(conn)
io.print("Client connected: {addr}")
while true {
data, err = net.tcp_read(conn, 1024)
if err {
io.print("Client disconnected: {addr}")
return
}
if str.len(data) == 0 { continue }
msg = str.trim(data)
io.print("[{addr}] {msg}")
_, err = net.tcp_write(conn, "echo: {msg}\n")
if err {
io.print("Write error: {err.message}")
return
}
}
}
listener, err = net.tcp_listen(":9000")
if err {
io.print("Listen error: {err.message}")
os.exit(1)
}
io.print("Echo server listening on :9000")
while true {
conn, err = net.tcp_accept(listener)
if err {
io.print("Accept error: {err.message}")
continue
}
spawn handle_client(conn)
}