Skip to content

Constants and Override

const declares a value fixed at compile time (UPPER_SNAKE_CASE by convention) — the compiler folds it throughout the program and rejects any attempt to reassign it:

const accepts an optional type annotation and can be declared inside functions.

03-const.zolo
Playground
// Feature: Compile-time constants with `const`
// Syntax: `const NAME = value` (typically UPPER_SNAKE_CASE)
// When to use: fixed values known at compile time — limits,
// versions, immutable configuration. Unlike `let`, `const` must
// be initialized with a constant expression.

// Numeric constant.
const PI = 3.14159
const MAX_RETRIES = 3

// String constant.
const APP_NAME = "Zolo"
const VERSION = "0.1.0"

// Optional type annotation.
const BUFFER_SIZE: int = 1024

print(PI)  // 3.14159
print(MAX_RETRIES)  // 3
print(APP_NAME)  // Zolo
print(VERSION)  // 0.1.0
print(BUFFER_SIZE)  // 1024

// `const` can also appear inside functions (local scope).
fn area(r: float) -> float {
  const TWO_PI = 6.28318
  return TWO_PI * r * r * 0.5
}

print(area(5.0))  // 78.5...
// Reassigning a `const` is an error (uncomment to test):
// PI = 3.14  // error: cannot assign to const

override sits between const (build-time) and let (runtime): the value is fixed at module load time, but the host can replace it via the ZOLO_OVERRIDE_<NAME> environment variable or the --set NAME=VALUE flag — without recompiling:

override PORT = 8080 defaults to 8080 but accepts --set PORT=9000 at runtime.

17-override.zolo
Playground
// Feature: `override` — load-time substitutable constants
// Syntax: `override NAME [: T] [= default]`
// When to use: configuration that you want to fix at build time most of
// the time, but allow the host (CLI flag, env var, embedder API) to
// substitute without recompiling. Sits between `const` (fixed at build)
// and `let` (computed at runtime).
//
// Two resolution channels are supported today:
//   1. env var `ZOLO_OVERRIDE_<KEY>` at load time
//   2. CLI flag `--set KEY=VALUE` (or `--set=KEY=VALUE`) passed to
//      `zolo run`
// Both fall back to the comptime-constant default when no host value is
// supplied. The `@id("custom-name")` decorator lets you choose a key
// shape that doesn't have to match the Zolo identifier (kebab-case,
// dotted-path, etc.).
//
// See `specs/override-declarations.md` for the full specification.

// Top-level only — overrides are part of the module's public interface.
override PORT: int = 8080
override MAX_CONNECTIONS: int = 1024
override DEBUG: bool = false
override APP_NAME: str = "zolo-server"

// Custom key via `@id`. Useful when the host's config uses kebab-case
// or dotted paths that the Zolo identifier can't carry.
override RATE_LIMIT: int = 100

fn main() {
  print("Starting {APP_NAME} on port {PORT}")
  print("Max connections: {MAX_CONNECTIONS}")
  print("Debug mode: {DEBUG}")
  print("Rate limit: {RATE_LIMIT} req/s")
}
// Run without overrides:
//   $ zolo run 17-override.zolo
//   Starting zolo-server on port 8080  ...
//
// Run with --set flag (preferred form):
//   $ zolo run 17-override.zolo --set PORT=9000 --set DEBUG=true \
//                               --set rate-limit-rps=200
//   Starting zolo-server on port 9000  ...
//
// Run with environment overrides (equivalent):
//   $ ZOLO_OVERRIDE_PORT=9000 ZOLO_OVERRIDE_DEBUG=true \
//     ZOLO_OVERRIDE_RATE_LIMIT_RPS=200 zolo run 17-override.zolo
//
// Hyphens and dots in `@id` keys are normalized to underscores in the
// env-var name (`rate-limit-rps` → `ZOLO_OVERRIDE_RATE_LIMIT_RPS`).
//
// Restrictions enforced by the compiler:
//
// 1. Default must be comptime-constant. Runtime calls don't compile.
//
//    override BAD = read_user_input()
//    // error[E_OverrideNotConst]: `override` default must be a
//    //                            comptime-constant expression
//
// 2. At least one of `: T` or `= default` is required.
//
//    override SOMETHING
//    // parse error: `override` requires either a type annotation
//    //              or a default value
//
// 3. `override` without a default forces the host to provide a value:
//
//    override REQUIRED: str
//    // running without ZOLO_OVERRIDE_REQUIRED set:
//    //   error: E_OverrideMissing: override `REQUIRED` has no default
//    //          and was not set via ZOLO_OVERRIDE_REQUIRED
//
// Difference vs. `const`:
//   const  — fixed at BUILD time; aggressive constant-folding allowed.
//   override — fixed at LOAD time; host can substitute before main runs.
//   let mut / var — runtime; can change during execution.

Challenge

Add override TIMEOUT: int = 30 to the example above and run it with --set TIMEOUT=5. Observe how the value changes without touching the source code.

enespt-br