Keywords Reference

EZ uses plain English keywords designed to be readable and beginner-friendly. If you’re coming from another language, some of these will look different from what you’re used to.

Variables & Constants

mut

Declares a mutable variable — a value that can change.

mut count = 0
count = 10  // allowed

mut name string = "Alice"  // explicit type annotation also works

Why “mut”? It stands for “mutable.” Use mut for values that will change during your program’s execution, like counters, user input, or calculated results.

const

Declares an immutable constant — a value that cannot change. Also used to define structs and enums.

const PI = 3.14159
const MAX_SIZE = 100

// Also used for type definitions
const Person struct {
    name string
    age int
}

Why “const”? It’s short for “constant.” Use const for values that should never change, like configuration settings, mathematical constants (PI), or type definitions.

Functions

do

Declares a function.

do greet(name string) {
    println("Hello, ${name}!")
}

do add(a, b int) -> int {
    return a + b
}

Why “do”? Functions do things. Reads naturally: “do greet” means “do the greet action.”

return

Exits a function and optionally returns a value.

do double(x int) -> int {
    return x * 2
}

do validate(n int) -> bool {
    if n < 0 {
        return false  // early return
    }
    return true
}

ensure

Guarantees a function call runs when the current function exits, regardless of how it exits. Used for cleanup like closing files or databases.

import @io

do process() {
    mut file, _ = io.open("data.txt", "r")
    ensure io.close(file)  // always runs when process() exits

    // ... work with file ...
    // io.close(file) runs automatically, even on early return
}

Multiple ensure statements run in reverse order (last registered runs first). See Functions - ensure for details.

or_return

Provides error propagation shorthand. When a call returns a non-nil error, or_return immediately returns from the enclosing function.

do load() -> (string, Error) {
    // Bare or_return: propagates the error with zero values
    mut content = read_file("data.txt") or_return
    mut parsed = json.decode(content) or_return
    return parsed, nil
}

// With custom fallback values:
mut content = read_file("data.txt") or_return "", error("failed to load")

The enclosing function must have Error as its last return type. See Functions - or_return for details.

Control Flow

if

Starts a conditional block. Executes code only if the condition is true.

if score >= 90 {
    println("A grade!")
}

or

Adds an alternative condition — like else if in other languages.

if score >= 90 {
    println("A")
} or score >= 80 {
    println("B")
} or score >= 70 {
    println("C")
}

Why “or”? Reads naturally: “if this, or that, or that.”

otherwise

The fallback case — like else in other languages.

if score >= 60 {
    println("Pass")
} otherwise {
    println("Fail")
}

Why “otherwise”? Reads like English: “if passing, celebrate; otherwise, study more.”

for

Numeric loop that iterates over a range.

for i in range(0, 5) {
    println(i)  // 0, 1, 2, 3, 4
}

for_each

Iterates over each item in a collection (arrays, strings, or maps).

mut names [string] = {"Alice", "Bob", "Charlie"}

for_each name in names {
    println("Hello, ${name}")
}

// With maps
mut ages map[string:int] = {"Alice": 30, "Bob": 25}
for_each k, v in ages {
    println("${k}: ${v}")
}

Why “for_each”? Explicit about looping over each item in a collection.

as_long_as

Loops while a condition is true — like while in other languages.

mut count = 0

as_long_as count < 5 {
    println(count)
    count++
}

Why “as_long_as”? Reads naturally: “keep going as long as this is true.”

while

Alias for as_long_as. Both are valid:

mut total = 0
while total < 100 {
    total += 10
}

loop

Infinite loop that runs until you break out of it.

mut attempts = 0

loop {
    attempts++
    if attempts >= 3 {
        break
    }
}

break

Immediately exits the current loop.

for i in range(0, 100) {
    if i == 5 {
        break  // stop at 5
    }
    println(i)
}

continue

Skips to the next iteration of the loop.

for i in range(0, 10) {
    if i % 2 == 0 {
        continue  // skip even numbers
    }
    println(i)  // only odd numbers
}

in

Used with for to iterate over a range, or to check if a value exists in a collection (arrays, ranges, or maps).

// In a for loop
for i in range(0, 10) {
    println(i)
}

// Array membership
mut nums [int] = {1, 2, 3}
if 2 in nums {
    println("Found it!")
}

// Map key membership
mut ages map[string:int] = {"Alice": 30}
if "Alice" in ages {
    println("Key exists!")
}

not_in

Checks if a value does not exist in a collection (arrays, ranges, or maps). !in is a shorthand alias.

mut nums [int] = {1, 2, 3}
if 5 not_in nums {
    println("Not found")
}

// !in is shorthand for not_in
mut ages map[string:int] = {"Alice": 30}
if "Bob" !in ages {
    println("Bob not in map")
}

when

Starts a pattern matching block — like switch in other languages.

mut day = 3

when day {
    is 1 { println("Monday") }
    is 2 { println("Tuesday") }
    is 3 { println("Wednesday") }
    default { println("Other day") }
}

Why “when”? Reads naturally: “when day is 1, do this.”

is

Specifies a case in a when block.

when value {
    is 1 { /* matches 1 */ }
    is 2, 3, 4 { /* matches 2, 3, or 4 */ }
    is range(5, 10) { /* matches 5-9 */ }
    default { /* fallback */ }
}

default

The fallback case in a when block — executes when no is case matches.

when status {
    is "active" { /* handle active */ }
    is "pending" { /* handle pending */ }
    default { /* handle all other cases */ }
}

Note: default is required unless using #strict with an enum that has all cases covered.

Type Conversion

cast

Converts values between types. Works with single values and arrays.

// Single value conversion
mut x = cast(42, u8)        // int -> u8
mut y = cast(3.14, int)     // float -> int
mut z = cast(65, char)      // int -> char

// Array element-wise conversion
mut bytes [byte] = {65, 66, 67}
mut u8_arr = cast(bytes, [u8])  // [byte] -> [u8]

Why “cast”? Explicitly converts (casts) a value from one type to another.

Note: Although cast() uses function-like syntax, it is a language keyword, not a regular function. The second argument must be a valid EZ type, which the compiler validates at check-time (before execution). This is why cast() is documented here rather than solely in built-in functions — though it also appears there for discoverability. See also: cast() in Built-in Functions.

Supported Conversions

Target TypeAccepted Source Types
intint, float, string, char, byte
floatfloat, int, string, byte, char
stringall types (uses string representation)
charchar, int, float, byte, string (len=1)
bytebyte, int, float, char, string
i8/i16/i32/i64/i128/i256int, float, string, byte, char
u8/u16/u32/u64/u128/u256int, float, string, byte, char
f32/f64float, int, string, byte, char
boolbool, int (0=false, else=true), string (“true”/“false”)

Array Conversions

For arrays, cast() applies the conversion to each element:

mut nums [int] = {1, 2, 3}
mut strs = cast(nums, [string])  // ["1", "2", "3"]

Error Handling

Invalid conversions produce errors:

// Range error with index info
mut result = cast([-1, 2, 3], [u8])
// Error: "cast failed at index 0: value -1 out of u8 range (0 to 255)"

Types

Primitive Types

KeywordDescription
intInteger (whole number)
uintUnsigned (non-negative) integer
floatFloating-point (decimal) number
stringText
charSingle character
boolBoolean (true or false)
byteUnsigned 8-bit value (0-255)
mut age = 25
mut price = 19.99
mut name = "Alice"
mut letter = 'A'
mut active = true

Sized Integers

For when you need precise control over size:

SignedUnsignedSize
i8u88 bits
i16u1616 bits
i32u3232 bits
i64u6464 bits
i128u128128 bits
i256u256256 bits
mut byte_val u8 = 255
mut big i64 = 9223372036854775807

struct

Defines a composite type with named fields.

const Point struct {
    x int
    y int
}

mut p = Point{x: 10, y: 20}

enum

Defines a type with a fixed set of named values.

const Status enum {
    PENDING
    ACTIVE
    DONE
}

mut s = Status.ACTIVE

map

Key-value collection type.

mut ages map[string:int] = {
    "Alice": 30,
    "Bob": 25
}

Modules

import

Brings a module into your file. Must be at the top.

import @math, @arrays
import "./mymodule"

using

Makes module contents available without a prefix.

import @math
using math

do main() {
    mut result = sqrt(16.0)  // No math. prefix needed
}

import and use

Combines importing and using in one statement:

import and use @arrays

do main() {
    mut nums [int] = {1, 2, 3}
    append(nums, 4)  // No arrays. prefix needed
}

Pointer Operations

new

Allocates a zero-initialized struct on the heap. Returns a pointer (^Type).

const Person struct {
    name string
    age int
}

mut p = new(Person)  // Returns ^Person
p^.name = "Alice"
p^.age = 30

addr

Gets the memory address of a variable.

mut x = 42
mut p = addr(x)  // ^int pointer
println(p^)       // 42

Visibility

By default, all user-declared functions, types, and variables are public — they can be accessed from other modules that import yours.

private

Makes a declaration private to its module. Private items cannot be accessed from outside the module.

// Private variable — only accessible within this module
private const INTERNAL_LIMIT = 1000

// Private function — only callable within this module
private do helper() {
    // ...
}

// Public function (default) — accessible from other modules
do get_count() -> int {
    helper()  // can call private function internally
    return 42
}

Why “private”? Hides implementation details so other modules only see what they need.

Boolean Values

true

Boolean true value.

false

Boolean false value.

mut isValid = true
mut hasError = false

nil

Represents the absence of a value. Used primarily with Error types to indicate success or check for errors.

import @io

do main() {
    mut content, err = io.read("data.txt")
    if err != nil {
        println("Error:", err.message)
        return
    }
    // err is nil, meaning no error occurred
    println(content)
}

Functions that can fail return nil for the error on success, or an Error on failure.

Quick Reference Table

EZ KeywordOther LanguagesPurpose
mutlet, varMutable variable
constconst, finalImmutable value
dofunction, func, fn, defDeclare function
orelse if, elifAlternative condition
otherwiseelseFallback condition
for_eachfor...of, for...in, foreachIterate collection
as_long_aswhileConditional loop
whilewhileConditional loop (alias)
loopwhile(true), loopInfinite loop
whenswitch, matchPattern matching
iscasePattern case
defaultdefault, _Fallback case
casttype casts, asType conversion
ensuredeferGuaranteed cleanup on function exit
or_return? (Rust), tryError propagation shorthand
newnew, mallocHeap-allocate struct (returns pointer)
nilnull, None, nilAbsence of a value
privateprivate, internalModule-private declaration
!innot inShorthand for not_in

For attributes (#doc, #flags, #strict, #suppress), see Attributes.

See Also

  • Control Flow — detailed control flow usage and examples
  • Functions — detailed function usage and examples
  • Variables — detailed variable usage and examples
  • Modules — detailed module system usage