Skip to content

Variables and Types

Variable Declarations #

Zolo has three ways to declare variables:

let — Immutable Binding

let x = 10
let name: str = "Zolo"

Once assigned, a let binding cannot be reassigned:

let x = 10
x = 20  // Error: cannot reassign immutable variable

let mut — Mutable Binding

let mut counter = 0
counter = counter + 1  // OK
counter += 1           // OK — compound assignment

const — Constant

const PI: f64 = 3.14159
const MAX_SIZE: int = 1024

Constants must have a value at declaration time and cannot be reassigned.

Type Annotations #

Type annotations are optional — Zolo infers types when possible:

let x = 42            // inferred: int
let y: f64 = 3.14     // explicit: f64
let name = "hello"    // inferred: str
let flag = true       // inferred: bool

Built-in Types #

Type Description Examples
int 64-bit integer 42, -7, 0
float 64-bit IEEE 754 float 3.14, -0.5, 1.0
decimal Exact decimal (~28 significant digits) 0.1d, 100d
bigdecimal Arbitrary-precision decimal 0.1bd, 1234567890123456789012345678bd
str String "hello", "world"
bool Boolean true, false
nil Null/absence of value nil

float — constants and methods

float exposes IEEE 754 constants as type-level properties (float.EPSILON, float.MAX, float.INFINITY, float.NAN, etc.) and comparison/predicate methods (.is_nan(), .is_finite(), .approx_eq(), etc.). See Float Precision & Decimal Types for the full reference.

decimal and bigdecimal — exact arithmetic

Use decimal (suffix d) and bigdecimal (suffix bd) when binary floating-point noise is unacceptable: money, totals, bookkeeping. Comparison with == is exact and does not trigger the float-equality lint. See Float Precision & Decimal Types for arithmetic, conversions, and methods.

Compound Types #

Arrays #

let arr: [int] = [1, 2, 3]
let names: [str] = ["Alice", "Bob"]
let empty: [int] = []

Arrays are 0-indexed:

let arr = [10, 20, 30]
print(arr[0])   // 10
print(arr[2])   // 30

Maps #

let scores: {str: int} = { "Alice": 95, "Bob": 87 }
let config = { "host": "localhost", "port": 8080 }

Tuples #

let point: (int, int) = (10, 20)
let pair: (str, int) = ("age", 25)

Optional Types #

The ? suffix makes a type optional (nullable):

let x: int? = 42       // has a value
let y: int? = nil       // no value

let name: str? = nil

Function Types #

let callback: fn(int) -> int = |x| x * 2
let predicate: fn(str) -> bool = |s| s.len() > 3

Generic Types #

let map: Map<str, int> = Map.new()
let result: Result<int, str> = Result.Ok(42)

Compound Assignment #

Zolo supports compound assignment operators:

let mut x = 10
x += 5     // x = 15
x -= 3     // x = 12
x *= 2     // x = 24
x /= 4     // x = 6
x %= 5     // x = 1

Shadowing #

You can redeclare a variable with the same name:

let x = 10
let x = x * 2     // shadows the previous x
let x = "hello"   // can even change type

Type System Notes #

  • Types are checked at compile time — no runtime cost
  • The type checker runs during compilation and reports errors with source locations
  • nil is only allowed for optional types (T?)
  • Zolo compiles to Lua, so types are erased at runtime
enespt-br