Examples
Real, copy-paste-ready code for common tasks. Click an example to view the code.
Basics
/*
* control_flow.ez - Conditionals and loops
*
* EZ uses:
* - if / or / otherwise (not else if / else)
* - when / is / default (pattern matching)
* - for with range()
* - for_each for collections
* - as_long_as (like while)
* - loop (infinite loop)
*/
const Season enum {
SPRING,
SUMMER,
FALL,
WINTER
}
do main() {
println("=== Control Flow in EZ ===")
println("")
// if / or / otherwise
println("-- Conditionals --")
mut score int = 85
if score >= 90 {
println("Grade: A")
} or score >= 80 {
println("Grade: B")
} or score >= 70 {
println("Grade: C")
} otherwise {
println("Grade: F")
}
// when/is with default (pattern matching)
println("")
println("-- When/Is with default --")
mut day int = 6
when day {
is 1, 2, 3, 4, 5 { println("Weekday") }
is 6, 7 { println("Weekend!") }
default { println("Invalid day") }
}
// when/is with range matching
println("")
println("-- When/Is with range --")
when score {
is range(90, 101) { println("Letter grade: A") }
is range(80, 90) { println("Letter grade: B") }
is range(70, 80) { println("Letter grade: C") }
is range(60, 70) { println("Letter grade: D") }
default { println("Letter grade: F") }
}
// #strict when/is (must cover all enum values, no default)
println("")
println("-- Strict When/Is (enum) --")
mut current = Season.SUMMER
#strict
when current {
is Season.SPRING { println("Flowers blooming") }
is Season.SUMMER { println("Sun is shining") }
is Season.FALL { println("Leaves falling") }
is Season.WINTER { println("Snow is falling") }
}
// for loop with range
println("")
println("-- For loop with range --")
println("Counting 1 to 5:")
for i in range(1, 6) {
println(" ${i}")
}
// Note: Descending ranges like range(5, 0) are now check-time errors (E9005)
// Use as_long_as with decrement if you need to count backwards:
println("")
println("-- Counting backwards --")
println("Countdown from 5:")
mut n int = 5
as_long_as n > 0 {
println(" ${n}")
n--
}
// for_each loop
println("")
println("-- For_each loop --")
mut fruits [string] = {"apple", "banana", "cherry"}
println("Fruits:")
for_each fruit in fruits {
println(" - ${fruit}")
}
// for_each with index
println("")
println("-- For_each with index --")
println("Numbered fruits:")
for_each i, fruit in fruits {
println(" ${i}: ${fruit}")
}
// for_each with string
println("")
println("Letters in 'EZ':")
for_each ch in "EZ" {
println(" ${ch}")
}
// as_long_as loop (while equivalent)
println("")
println("-- As_long_as loop --")
mut count int = 0
as_long_as count < 3 {
println(" count = ${count}")
count++
}
// loop (infinite loop, use break to exit)
println("")
println("-- Loop (infinite loop) --")
mut x int = 0
loop {
if x == 3 {
break
}
println(" x = ${x}")
x++
}
// break and continue
println("")
println("-- Break and Continue --")
println("Numbers 1-10, skip evens, stop at 7:")
for i in range(1, 11) {
if i == 7 {
break
}
if i % 2 == 0 {
continue
}
println(" ${i}")
}
}
/*
* functions.ez - Defining and calling functions
*
* Functions in EZ use the 'do' keyword.
* Return types are specified with '->'
* Named returns use '-> (name type)' syntax (labels only).
*/
do main() {
println("=== Functions in EZ ===")
println("")
// Calling a simple function
greet()
// Function with parameters
greet_person("Alice")
greet_person("Bob")
// Function with return value
mut sum int = add(5, 3)
println("add(5, 3) = ${sum}")
// Function with multiple parameters
mut result float = calculate(10.0, 5.0, 2.0)
println("calculate(10, 5, 2) = ${result}")
// Recursive function
mut fact int = factorial(5)
println("factorial(5) = ${fact}")
// Function returning a string
mut msg string = get_greeting("World")
println(msg)
// Named return values (labels for documentation)
println("")
println("--- Named Returns ---")
mut area int = rect_area(5, 3)
println("rect_area(5, 3) = ${area}")
mut x int, y int = swap(10, 20)
println("swap(10, 20) = ${x}, ${y}")
mut name string, age int, active bool = get_user()
println("get_user() = ${name}, ${age}, ${active}")
mut mn int, mx int = min_max(7, 3, 9, 1, 5)
println("min_max(7,3,9,1,5) = min:${mn}, max:${mx}")
}
// Simple function with no parameters or return
do greet() {
println("Hello!")
}
// Function with a parameter
do greet_person(name string) {
println("Hello, ${name}!")
}
// Function with return type
do add(a int, b int) -> int {
return a + b
}
// Multiple parameters with shared types
do calculate(x float, y float, z float) -> float {
return (x + y) * z
}
// Recursive function
do factorial(n int) -> int {
if n <= 1 {
return 1
}
return n * factorial(n - 1)
}
// Function returning a string
do get_greeting(name string) -> string {
return "Welcome, ${name}!"
}
// Named return: single value
// Names are labels only — you must declare your own variables
do rect_area(w int, h int) -> (area int) {
mut area int = w * h
return area
}
// Named return: multiple values
do swap(a int, b int) -> (x int, y int) {
mut x int = b
mut y int = a
return x, y
}
// Named return: mixed types
do get_user() -> (name string, age int, active bool) {
mut name string = "Alice"
mut age int = 30
mut active bool = true
return name, age, active
}
// Named return: shared type shorthand
do min_max(a int, b int, c int, d int, e int) -> (lo, hi int) {
mut lo int = a
mut hi int = a
if b < lo { lo = b }
if c < lo { lo = c }
if d < lo { lo = d }
if e < lo { lo = e }
if b > hi { hi = b }
if c > hi { hi = c }
if d > hi { hi = d }
if e > hi { hi = e }
return lo, hi
}
/*
* mutable_params.ez - Mutable vs Read-Only Parameters
*
* By default, function parameters are read-only.
* Use & to allow a function to modify its parameter.
*/
const Person struct {
name string
age int
}
do main() {
println("=== Mutable Parameters ===")
println("")
// Create a person
mut alice Person = Person{name: "Alice", age: 30}
println("Initial: ${alice.name} is ${alice.age}")
// Read-only: get_info just reads the data
mut info string = get_info(alice)
println("Info: ${info}")
// Mutable: birthday modifies the person
birthday(&alice)
println("After birthday: ${alice.name} is ${alice.age}")
// Another birthday
birthday(&alice)
println("After another birthday: ${alice.name} is ${alice.age}")
// Arrays work the same way
println("")
println("-- Arrays --")
mut scores [int] = {85, 90, 78}
println("Before: ${scores}")
// Mutable: add_bonus modifies the array
add_bonus(&scores, 5)
println("After +5 bonus: ${scores}")
// Read-only: calculate_average just reads
mut avg float = calculate_average(scores)
println("Average: ${avg}")
}
// Read-only parameter (no &)
// Can read p but cannot modify it
do get_info(p Person) -> string {
// p.age = 100 // ERROR: cannot modify read-only parameter
return "${p.name}, age ${p.age}"
}
// Mutable parameter (with &)
// Can modify p
do birthday(&p Person) {
p.age = p.age + 1
}
// Read-only array parameter
do calculate_average(nums [int]) -> float {
mut sum int = 0
for_each n in nums {
sum = sum + n
}
return float(sum) / float(len(nums))
}
// Mutable array parameter
do add_bonus(&scores [int], bonus int) {
for i in range(0, len(scores)) {
scores[i] = scores[i] + bonus
}
}
/*
* references.ez - Copy-by-default and explicit references
*
* EZ uses copy-by-default for assignment:
* - Assigning structs, arrays, or maps creates independent copies
* - Use ref() when you need shared state
* - Use copy() for explicit copying when intent needs to be clear
*/
const Point struct {
x int
y int
}
do main() {
println("=== References in EZ ===")
println("")
// ==================== COPY-BY-DEFAULT ====================
println("-- Copy-by-Default --")
println("Assignment creates independent copies (safe by default)")
println("")
// Structs are copied
mut p1 Point = Point{x: 10, y: 20}
mut p2 Point = p1 // p2 is a COPY of p1
p2.x = 999
println("p1 = Point{x: 10, y: 20}")
println("p2 = p1")
println("p2.x = 999")
println("")
println("Result: p1.x = ${p1.x}, p2.x = ${p2.x}")
println("p1 is unchanged because p2 is an independent copy")
println("")
// Arrays are copied too
mut arr1 [int] = {1, 2, 3}
mut arr2 [int] = arr1 // arr2 is a COPY of arr1
arr2[0] = 999
println("arr1 = {1, 2, 3}")
println("arr2 = arr1")
println("arr2[0] = 999")
println("")
println("Result: arr1[0] = ${arr1[0]}, arr2[0] = ${arr2[0]}")
println("arr1 is unchanged because arr2 is an independent copy")
println("")
// ==================== EXPLICIT REFERENCES ====================
println("-- Explicit References with ref() --")
println("Use ref() when you WANT shared state")
println("")
// Create a shared reference to a struct
mut p3 Point = Point{x: 100, y: 200}
mut p4 = ref(p3) // p4 SHARES state with p3
p4.x = 500
println("p3 = Point{x: 100, y: 200}")
println("p4 = ref(p3)")
println("p4.x = 500")
println("")
println("Result: p3.x = ${p3.x}, p4.x = ${p4.x}")
println("Both changed because p4 is a REFERENCE to p3")
println("")
// ref() works on primitives too
mut counter int = 0
mut alias = ref(counter)
alias = 42
println("counter = 0")
println("alias = ref(counter)")
println("alias = 42")
println("")
println("Result: counter = ${counter}, alias = ${alias}")
println("Both are 42 because alias references counter")
println("")
// ==================== WHEN TO USE EACH ====================
println("-- When to Use Each --")
println("")
println("Use assignment (=) when you want:")
println(" - Independent copies that can be modified separately")
println(" - Safe default behavior without side effects")
println("")
println("Use ref() when you want:")
println(" - Multiple variables to share the same data")
println(" - Changes through one variable to affect all references")
println(" - Performance optimization (avoid copying large data)")
}
/*
* error_handling.ez - Errors as values
*
* EZ uses explicit error handling:
* - Functions return (T, Error) tuples
* - Check errors by comparing to nil
* - Use error() to create error values
*
* No exceptions. No try/catch. Errors are just values.
*/
do main() {
// Calling a function that may fail
println("-- Basic error handling --")
mut result, err = divide(10, 3)
if err != nil {
println("Error: ${err}")
} otherwise {
println("10 / 3 = ${result}")
}
// Handling the error case
mut result2, err2 = divide(10, 0)
if err2 != nil {
println("10 / 0 failed: ${err2}")
} otherwise {
println("10 / 0 = ${result2}")
}
println("")
// Another fallible function
println("-- Parsing with errors --")
mut n, parse_err = parse_number("42")
if parse_err != nil {
println("parse failed: ${parse_err}")
} otherwise {
println("parse_number(\"42\") = ${n}")
}
mut bad, bad_err = parse_number("abc")
if bad_err != nil {
println("parse_number(\"abc\") failed: ${bad_err}")
} otherwise {
println("parsed: ${bad}")
}
mut neg, neg_err = parse_number("-5")
if neg_err != nil {
println("parse_number(\"-5\") failed: ${neg_err}")
} otherwise {
println("parsed: ${neg}")
}
}
// A function that returns a result or an error
do divide(a int, b int) -> (int, Error) {
if b == 0 {
return 0, error("division by zero")
}
return a / b, nil
}
// Another fallible function
do parse_number(s string) -> (int, Error) {
for_each ch in s {
if ch < '0' {
return 0, error("invalid character: ${ch}")
}
if ch > '9' {
return 0, error("invalid character: ${ch}")
}
}
return int(s), nil
}
Data Structures
/*
* pointers.ez - Pointers and heap allocation
*
* EZ has pointers for when you need indirection.
* ^Type — pointer type (e.g. ^int, ^Person)
* addr(x) — get the address of x
* p^ — dereference pointer p
* new(T) — allocate a zero-initialized T on the heap
*
* Every dereference is nil-checked at runtime.
*/
const Point struct {
x int
y int
}
do main() {
// addr() gives you a pointer to an existing variable
println("-- Pointers to local variables --")
mut value int = 42
mut p ^int = addr(value)
println("value = ${value}")
println("p^ = ${p^}")
// Modifying through the pointer changes the original
p^ = 100
println("After p^ = 100: value = ${value}")
println("")
// new() allocates a zero-initialized struct on the heap
println("-- Heap allocation with new() --")
mut pt ^Point = new(Point)
println("new(Point) -> x: ${pt^.x}, y: ${pt^.y}")
// Set fields through the pointer
pt^.x = 10
pt^.y = 20
println("After assignment -> x: ${pt^.x}, y: ${pt^.y}")
println("")
// Passing pointers to functions
println("-- Pointers in functions --")
mut counter int = 0
println("Before: counter = ${counter}")
increment_ptr(addr(counter))
increment_ptr(addr(counter))
increment_ptr(addr(counter))
println("After 3 increments: counter = ${counter}")
}
// A function that takes a pointer and modifies the value it points to
do increment_ptr(p ^int) {
p^ = p^ + 1
}
Algorithms
/*
* fizzbuzz.ez - The classic FizzBuzz problem
*
* Print numbers 1 to 100, but:
* - For multiples of 3, print "Fizz"
* - For multiples of 5, print "Buzz"
* - For multiples of both, print "FizzBuzz"
*/
do main() {
println("=== FizzBuzz ===")
println("")
for i in range(1, 101) {
if i % 15 == 0 {
println("FizzBuzz")
} or i % 3 == 0 {
println("Fizz")
} or i % 5 == 0 {
println("Buzz")
} otherwise {
println("${i}")
}
}
}
/*
* fibonacci.ez - The Fibonacci sequence
*
* Each number is the sum of the two preceding ones.
* 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
*/
do main() {
println("=== Fibonacci Sequence ===")
println("")
// Print first 20 Fibonacci numbers
println("First 20 Fibonacci numbers:")
for i in range(0, 20) {
println(" fib(${i}) = ${fibonacci(i)}")
}
// Sum of first 10
println("")
mut sum int = 0
for i in range(0, 10) {
sum = sum + fibonacci(i)
}
println("Sum of first 10: ${sum}")
}
// Recursive Fibonacci
do fibonacci(n int) -> int {
if n <= 0 {
return 0
}
if n == 1 {
return 1
}
return fibonacci(n - 1) + fibonacci(n - 2)
}
/*
* primes.ez - Finding prime numbers
*
* A prime number is only divisible by 1 and itself.
*/
do main() {
println("=== Prime Numbers ===")
println("")
// Check specific numbers
println("Checking individual numbers:")
println(" is_prime(2) = ${is_prime(2)}")
println(" is_prime(17) = ${is_prime(17)}")
println(" is_prime(20) = ${is_prime(20)}")
println(" is_prime(97) = ${is_prime(97)}")
// Find primes up to 50
println("")
println("Prime numbers up to 50:")
mut count int = 0
for n in range(2, 51) {
if is_prime(n) {
println(" ${n}")
count = count + 1
}
}
println("")
println("Found ${count} primes")
}
// Check if a number is prime
do is_prime(n int) -> bool {
if n < 2 {
return false
}
if n == 2 {
return true
}
if n % 2 == 0 {
return false
}
mut i int = 3
as_long_as i * i <= n {
if n % i == 0 {
return false
}
i = i + 2
}
return true
}
Modules & Standard Library
/*
* modules.ez - Organizing code with modules
*
* EZ modules are just files and directories:
* import @name — standard library module
* import "./file" — local file (file.ez)
* import "./dir" — local directory (all .ez files merge)
* import alias @name — import with an alias
* import and use @mod — import and use without prefix
*
* No package manager. No config files. Just files.
*/
import @strings
import @math
import s @strings // alias: use s.trim() instead of strings.trim()
do main() {
// Standard library modules are prefixed with @
println("-- Standard library imports --")
mut text string = " hello world "
println("strings.trim: '${strings.trim(text)}'")
println("math.abs(-5): ${math.abs(-5)}")
println("")
// Aliased imports use the alias as prefix
println("-- Aliased imports --")
println("s.to_upper: '${s.to_upper("hello")}'")
println("")
// Module identity comes from filenames:
// helpers.ez -> module "helpers"
// models/types.ez -> module "models"
// models/funcs.ez -> also module "models" (merged)
//
// Import local modules with relative paths:
// import "./helpers" -> single file
// import "./models" -> directory (all files merge)
// import h "./helpers" -> aliased local module
println("-- How modules work --")
println("1. One file = one module (filename is the name)")
println("2. One directory = one module (all files merge)")
println("3. No module declarations needed")
println("4. No package.json, no go.mod, no Cargo.toml")
}
/*
* using_stdlib.ez - Using the Standard Library
*
* EZ ships with many built-in modules. Import them with @name.
* No package manager needed — everything ships with the compiler.
*/
import @math, @strings, @arrays, @maps, @time
do main() {
// @math — common math operations
println("-- @math --")
println("math.abs(-42) = ${math.abs(-42)}")
println("math.sqrt(16.0) = ${math.sqrt(16.0)}")
println("math.pow(2.0, 10.0) = ${math.pow(2.0, 10.0)}")
println("math.min(5, 3) = ${math.min(5, 3)}")
println("")
// @strings — string manipulation
println("-- @strings --")
mut text string = " Hello, World! "
println("trim: '${strings.trim(text)}'")
println("upper: '${strings.to_upper(text)}'")
println("lower: '${strings.to_lower(text)}'")
mut fruits string = "apple,banana,cherry"
mut parts [string] = strings.split(fruits, ",")
println("split: ${parts}")
println("join: '${strings.join(parts, " | ")}'")
println("")
// @arrays — array utilities
println("-- @arrays --")
mut nums [int] = {1, 2, 3, 4, 5}
println("first: ${arrays.get_first(nums)}")
println("last: ${arrays.get_last(nums)}")
mut reversed [int] = arrays.reverse(nums)
println("reverse: ${reversed}")
mut sliced [int] = arrays.slice(nums, 1, 4)
println("slice(1,4): ${sliced}")
println("contains(3): ${arrays.contains(nums, 3)}")
mut grow [int] = {10, 20}
arrays.append(grow, 30)
println("after append: ${grow}")
println("")
// @maps — map utilities
println("-- @maps --")
mut scores map[string:int] = {"alice": 95, "bob": 87, "charlie": 92}
mut keys [string] = maps.get_keys(scores)
println("keys: ${keys}")
mut vals [int] = maps.get_values(scores)
println("values: ${vals}")
println("")
// @time — current time
println("-- @time --")
mut now int = time.now()
println("now (unix): ${now}")
println("year: ${time.year(now)}")
}