Zef is a dynamically-typed, object-oriented scripting language with first-class functions, closures, and garbage collection. It combines a clean, expressive syntax with powerful features like class-based inheritance, nested classes, and a flexible package system.
- Class-Based Object-Oriented Programming - Full support for classes, inheritance, and method overriding
- First-Class Functions - Functions are objects that can be passed around, stored in variables, and returned from other functions
- Closures - Lexical scoping with closure capture for powerful functional programming patterns
- Nested Classes - Classes can be defined inside other classes and methods, with access to outer scopes
- Accessors - Convenient
readableandaccessiblekeywords for getter/setter generation - Packages - Namespace system for organizing code
- Garbage Collection - Concurrent and parallel garbage collector
- Static Members - Class-level variables and methods
- Dynamic Inheritance - Class inheritance can be determined at runtime
Zef uses Meson as its build system.
- Fil-C++ version 0.678 or later
- Meson build system
- Ninja build tool
# Clone the repository
git clone <repository-url>
cd zef
# Set up the build directory
CXX=/opt/fil/bin/fil++ meson setup build
# Compile
cd build && ninjaThe compiled binary will be at build/zef.
Declare variables with the my keyword:
my x = 42
my name = "Alice"
my pi = 3.14159
Define functions with the fn keyword:
# Function with parameters
fn greet(name) {
println("Hello, " + name)
}
# Function returning a value
fn add(a, b) {
a + b # Last expression is returned
}
# Anonymous functions / lambdas
fn makeMultiplier(factor) {
fn (x) x * factor # Returns a closure
}
my double = makeMultiplier(2)
println(double(5)) # Output: 10
class Point {
my x, y
# Constructor
fn (inX, inY) {
x = inX
y = inY
}
# Method with explicit return
fn distanceFromOrigin {
(x * x + y * y).sqrt
}
# Method returning expression directly
fn toString "Point(" + x.toString + ", " + y.toString + ")"
}
my p = Point(3, 4)
println(p.toString) # Output: Point(3, 4)
class Shape {
fn area 0
}
class Circle : Shape {
my radius
fn (r) radius = r
fn area 3.14159 * radius * radius
}
class Rectangle : Shape {
my width, height
fn (w, h) {
width = w
height = h
}
fn area width * height
}
my shapes = [Circle(5), Rectangle(3, 4)]
my i = 0
while (i < shapes.size) {
println(shapes[i].area)
i += 1
}
Zef provides convenient accessors for properties:
class Person {
readable name # Read-only property with auto getter
accessible age # Read-write property with getter and setter
static my count = 0 # Static class variable
fn (inName) {
name = inName
age = 0
Person.count += 1
}
}
my p = Person("Alice")
println(p.name) # OK: reading readable property
# p.name = "Bob" # Error: cannot write to readable
p.age = 25 # OK: writing to accessible
println(p.age) # OK: reading accessible
println(Person.count) # Access static via class
my nums = [1, 2, 3]
nums.push(4)
nums.push(5)
println(nums) # Output: [1, 2, 3, 4, 5]
println(nums[0]) # Output: 1 (zero-indexed)
println(nums.size) # Output: 5
nums[2] = 100
println(nums) # Output: [1, 2, 100, 4, 5]
Organize your code with packages:
package math {
fn add(a, b) a + b
fn subtract(a, b) a - b
package geometry {
class Point {
my x, y
fn (a, b) { x = a; y = b }
fn toString "(" + x.toString + ", " + y.toString + ")"
}
}
}
# Use package members
println(math.add(2, 3))
my p = math.geometry.Point(1, 2)
println(p.toString)
# Packages can be extended
package math {
fn multiply(a, b) a * b
}
# If statements
my x = 42
if (x > 50) {
println("big")
} else if (x > 25) {
println("medium")
} else {
println("small")
}
# While loops
my i = 0
while (i < 5) {
println(i)
i += 1
}
Zef supports powerful patterns combining nested classes with closures:
fn makeCounter {
my count = 0
class Counter {
fn () { } # Constructor
fn increment {
count += 1
count
}
fn decrement {
count -= 1
count
}
fn get count
}
Counter()
}
my c1 = makeCounter()
my c2 = makeCounter()
println(c1.increment) # 1
println(c1.increment) # 2
println(c2.increment) # 1 (separate closure)
Zef allows runtime determination of base classes:
fn makeBaseClass(value) {
class Base {
readable val
fn () val = value
}
Base
}
my x = 42
class MyClass : if (x == 42) makeBaseClass(100) else makeBaseClass(200) {
fn () super()
}
println(MyClass().val) # Output: 100
The project includes a comprehensive test suite. Tests are run using the run-tests Ruby script:
# Build first
CXX=/opt/fil/bin/fil++ meson setup build && ninja -C build
# Run all tests
./run-tests
# Run with verbose output
./run-tests --verbose
# Run without strict error matching
./run-tests --no-strict-errorTests are located in the tests/ directory. Each test file has:
.zef- The test script.zef.expected- Expected output (for success tests).zef.error- Expected error message (for error tests).zef.memlimit- Optional memory limit in kB (for GC tests)
./build/zef myprogram.zefSee the tests/ directory for many examples of Zef code, including:
deltablue.zef- Constraint solver benchmarkrichards.zef- Operating system simulator benchmarknbody.zef- N-body physics simulationsplay.zef- Splay tree benchmark