Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Zebra Syntax Cheat Sheet

One-page reference for Zebra syntax. Print this page!


Variables & Types

var x = 42                              # int (inferred)
var s = "hello"                         # str
var f = 3.14                            # float
var b = true                            # bool
var c = 'x'                             # char

var x: int = 42                       # explicit type
var y: int? = nil                     # nullable type

Functions

def add(a: int, b: int): int
    return a + b

var result = add(2, 3)                  # 5

def no_return()
    print("Just print")

Classes

class Person
    var name: str = ""
    var age: int = 0

    cue init(name: str, age: int)
        this.name = name
        this.age = age

    def describe(): str
        return "${name} is ${age}"

var person = Person("Alice", 30)

Cues (methods the compiler calls)

Nine, and only nine: init, toString, equals, hash, compare, iter, next, begin, end. Anything else is a def. There is no cue deinit; use using (and cue begin / cue end) for a release step. Writing a cue as def (def toString) is refused. Full story: Chapter 07, "Cues".

class Money
    var cents: int
    cue init(cents: int)                # Money(5)
        .cents = cents
    cue toString(): str                 # print(m), "${m}"
        return "${.cents}c"
    cue equals(other: Money): bool      # ==, !=
        return .cents == other.cents
    cue hash(): int                     # HashMap key / Set element (needs equals)
        return .cents
    cue compare(other: Money): int      # < <= > >=, list.sort() (needs equals)
        return .cents - other.cents

class Count3
    var n: int = 3
    cue next(): int?                    # for x in obj; nil = done
        if .n == 0: return nil
        .n = .n - 1
        return .n + 1
    # cue iter(): I -- return an object whose type has `cue next` (fresh per loop)

class Section
    var name: str
    cue init(name: str)
        .name = name
    cue begin()                         # using obj: on entry
        print("<${.name}>")
    cue end()                           # using obj: on exit
        print("</${.name}>")

def evens(limit: int): Iter(int)        # generator: the compiler writes `cue next`
    var i = 0
    while i < limit
        yield i
        i = i + 2

def main()
    print(Money(5) < Money(7))          # true
    for x in Count3()
        print(x)                        # 3 2 1
    for e in evens(5)
        print(e)                        # 0 2 4
    using Section("p")
        print("hi")                     # <p> hi </p>

Without equals, == on a class is identity. Without compare, < and sort() on a class do not build. Structs take the same cues, by value; @derive(Debug, Eq, Hash) writes the first three.


Interfaces

interface Shape
    def area(): float
    def perimeter(): float

class Circle implements Shape
    var radius: float = 0.0

    def area(): float
        return 3.14159 * radius * radius

    def perimeter(): float
        return 2.0 * 3.14159 * radius

Structs & Unions

struct Point
    var x: int
    var y: int

union Value
    int_: int
    str_: str
    none_

# Pattern matching
branch v
    on Value.int_ as n
        print(n)
    on Value.str_ as s
        print(s)
    else
        pass

Composition & Mixins

Zebra has no class inheritance. Reuse via interfaces (Ch 08), mixins (adds), or composition (fields).

# Mixin — shared methods pulled into multiple classes:
mixin Loggable
    def log(message: str)
        print("[log] ${message}")

class UserService adds Loggable
    cue init()
        pass
    # `log()` is now a method on UserService.

# Composition — has-a, not is-a:
class Storage
    var path: str = ""

class Report
    var storage: Storage      # field-held helper

    cue init(p: str)
        storage = Storage()
        storage.path = p

See Chapter 09 for the full picture.


Control Flow

# If/Else if/Else
if x > 10
    print("Large")
else if x > 5
    print("Medium")
else
    print("Small")

# While loop
var i = 0
while i < 10
    print(i)
    i = i + 1

# For loop
for item in items
    print(item)

for i in 0..10
    print(i)  # 0, 1, 2, ..., 9

# Break & Continue
while true
    if x == 5
        break
    if x == 2
        x = x + 1
        continue
    print(x)
    x = x + 1

Operators

# Arithmetic (integer overflow stops the program, in every build)
10 + 5, 10 - 5, 10 * 5, 10 / 5, 10 % 3

# Wrapping / saturating integer arithmetic
b +% 10, b -% 10, b *% 2, -%b             # wrap around the type's range
b +| 10, b -| 10, b *| 2, b <<| 1         # clamp at the type's bounds

# Typed literals
300_i16, 5_u8, 7u, 0xFF_u8, 1.5_f32

# Comparison
10 > 5, 10 < 5, 10 >= 5, 10 <= 5
10 == 5, 10 != 5

# Logical
true and false
true or false
not true

# String
"hello" + " world"
"Value: ${x}"                           # interpolation

Collections

# List
var numbers = List(int)()
numbers.add(1)
numbers.add(2)
for num in numbers
    print(num)
numbers.count()
numbers.at(0)
numbers.contains(1)
numbers.remove(1)

# HashMap
var map = HashMap(str, int)()
map.put("a", 1)
map.fetch("a")                        # retrieve value
map.contains("a")
map.remove("a")
for key, value in map
    print("${key}: ${value}")

Strings

var text = "Hello, World!"

# Properties & Methods
text.len                                # length
text.upper()                            # uppercase
text.lower()                            # lowercase
text.contains("World")                  # substring search
text.startsWith("Hello")                # prefix check
text.endsWith("!")                      # suffix check
text.split(",")                         # split to List(str)
text.replace("World", "Zebra")          # replace all occurrences
text.trim()                             # remove whitespace
text.indexOf("World")                   # find position (-1 if not found)
text.reverse()                          # reverse string
text.repeat(3)                          # repeat N times

# Type conversion
"42".toInt()                            # int (0 on bad input; "42".tryInt() is int?)
"3.14".toFloat()                        # float (0.0 on bad input; tryFloat() is float?)
42.toString()                           # "42"

Error Handling

# Functions that can fail use throws
def parse(text: str): int throws
    if text.len == 0
        raise "Empty input"
    return 42

# Catch expression (inline fallback)
var value = parse("abc") catch 0

# Method-level catch (there is no try/catch block; a catch clause
# attaches to a def, at the same indent as def)
def attempt()
    var v = parse("")
    print(v)
catch |err|
    print("Error: ${err.message}")

# Catch expression fallback — no binding needed for a fixed value
var result = parse("x") catch -1

Nil Safety

var x: int? = 42                      # Can be int or nil
var y: int? = nil                     # Explicitly nil

# Safe check
if x != nil
    var safe_x = x + 1                  # Safe now

Generics

# Generics are class-scoped in Zebra — there is no free top-level generic
# function; a generic method lives on a generic class:
class Box(T)
    var item: T?

    def store(value: T)
        this.item = value

    def retrieve(): T?
        return this.item

var box = Box(str)()
box.store("hello")

Pipelines

var result = text -> .trim() -> .upper() -> .split(" ")

# Equivalent to:
var trimmed = text.trim()
var upper = trimmed.upper()
var parts = upper.split(" ")

File I/O

# Read file (File.read/write are not `throws`; guard with File.exists)
var content = File.read("file.txt")

# Write file
File.write("output.txt", content)

# Check existence
if File.exists("file.txt")
    print("File exists")

Regular Expressions

var pattern = Regex.compile("[a-z0-9]+@[a-z]+\\.[a-z]+")

pattern.match("user@example.com")       # bool (the WHOLE string must match)
pattern.find(text)                      # str (first match, "" if none)
pattern.findAll(text)                   # List(str) (all matches)
pattern.replace(text, "X")              # str (replaces every match)
pattern.split(text)                     # List(str) (split by match)

System Access

sys.args()                              # List(str): command-line args
sys.exit(code)                          # Exit program
Arg.parse()                             # Structured argument parsing

Modules

use MathUtils                           # Import module
use ast exposing Stmt, Expr, TypeRef    # Selective import

Math Module

Math.PI                                 # 3.14159...
Math.E                                  # 2.71828...
Math.sin(x)                             # Trig functions
Math.sqrt(x)                            # Square root
Math.pow(x, y)                          # Power
Math.abs(x)                             # Absolute value
Math.min(a, b)                          # Minimum
Math.max(a, b)                          # Maximum
Math.floor(x)                           # Round down
Math.ceil(x)                            # Round up

Static Methods

class MathUtils
    static
        def add(a: int, b: int): int
            return a + b

MathUtils.add(2, 3)                     # Call without instance

The keyword is static (the older shared was renamed in 2026-04-19).


Contracts (require / ensure / invariant)

class Counter
    var count: int = 0

    invariant
        count >= 0

    def increment(): int
        ensure
            result == old count + 1     # `result` = return value; `old expr` = pre-call snapshot
        count = count + 1
        return count

    def decrement_by(n: int)
        require
            n > 0
            n <= count
        count = count - n

Pass --turbo to strip all contract checks. It is independent of --release (which optimises); a shipping build uses both: zebra --release --turbo app.zbr. See Chapter 14.


Reflection — Reflect.* / @reflectable

# Tier 1: static field/type-name arrays:
class User
    var name: str = ""
    var age: int = 0

print(Reflect.className(u))  # "User"
for n in Reflect.fieldNames(u)
    print(n)

# Tier 3: strict JSON deserialization
@reflectable
class User
    var name: str = ""
    var age: int = 0

if Json.parseStrict(User, src) as u
    print(u.name)

Strict semantics: missing key, type mismatch, or extra key → nil. Scope-1 fields: int / float / bool / str.


Comments

# Single-line comment

# Multi-line comments
# are just multiple
# single-line comments

Keywords Quick Reference

KeywordUse
varDeclare variable
defDefine function
classDefine class
structDefine value type
unionDefine tagged union
enumDefine enumeration
interfaceDefine interface
isMember attribute / type check
implementsImplement interface
if, else if, elseConditional
whileWhile loop
forFor loop
breakExit loop
continueSkip iteration
branchPattern matching
onPattern case
returnReturn from function
raiseSignal an error
throwsMark function as fallible
catchError handling (expr catch fallback, method-level catch)
exceptStruct update copy
nilNull value
true, falseBoolean literals
asBinding clause (if x as n, branch on V as r)
staticType-associated (class-level) member
mixinDeclare a reusable bag of methods
addsInclude a mixin into a class
requirePrecondition contract
ensurePostcondition contract
invariantClass invariant contract
resultReturn-value reference inside ensure
oldPre-call snapshot inside ensure
assertInline sanity check
allocateBounded-scope memory block (allocate Arena())
cueMethod the compiler calls for you (cue init, cue toString, cue equals, ...)
yieldProduce the next value in a generator (a def returning Iter(T))
capturePer-closure persistent state, at the top of a lambda body
sigNamed function type (sig Predicate(item: str): bool)
usingBlock scoped by a resource with cue begin() / cue end() (using g.vbox(...) in GUIs)
withContextual receiver (with obj → bare x = 5 means obj.x = 5)
orelseNil fallback (maybe orelse 0)
toOnly as a method name, e.g. for i in 0.to(10); there is no x to T conversion operator — use .toInt(), .toFloat(), .toString()
thisCurrent object reference
useImport module
@reflectableOpt class into Tier-3 reflection (Json.parseStrict)
exposingSelective import
whereType constraint

Quick Type Reference

TypeExampleDefault
int420
float3.140.0
booltruefalse
str"hello"""
char'x'''
T?42 or nilnil
List(T)List(int)()empty
HashMap(K,V)HashMap(str, int)()empty
^T^Nodeheap pointer

Operator Precedence

  1. () — function call, array access
  2. not — logical NOT
  3. *, /, % — multiplication, division, modulo
  4. +, - — addition, subtraction
  5. <, >, <=, >=, ==, != — comparison
  6. and — logical AND
  7. or — logical OR
  8. = — assignment

Print this page for quick reference!

For more details, see the full book or use the Troubleshooting guide (Appendix C).