Zekken Documentation

Type system, runtime values, and method/cast behavior.

Section 3 of 8

Types

Declared Types#

These are the types you can write in annotations:

  • int - 64-bit integer
  • float - 64-bit floating point
  • string - UTF-8 text
  • bool - true/false
  • arr - ordered array
  • obj - key/value object
  • fn - function/lambda value type in declarations

Note: these type names are reserved keywords. You cannot use a type name as a variable identifier (for example let obj: obj = ...) because the lexer will treat obj as a type token, not an identifier.

// Bad (variable name collides with the obj type keyword)
let obj: obj = { b: 1 };

// Good
let headers: obj = { b: 1 };

How The Type System Works#

Zekken is explicitly typed: declarations require a type annotation, and values are checked against that type during execution. This is different from traditional compile-time static typing.

  • No inferred typing: let x = 10 is a syntax error.
  • Declaration checks: the initializer value must match the declared type.
  • Assignment checks: reassigning a variable must keep the same declared type.
  • Function parameter checks: argument values are validated against parameter types at call time.
  • Containers are not generic: arr and obj can hold mixed runtime values.
// 1) Declaration type check
let n: int = 10;
let bad: int = 3.14; // Type Error (int <- float)

// 2) Assignment type check
let x: string = "ABC123";
x = 123 // Type Error (string <- int)

// 3) Mixed containers (no generics like arr<int>)
let mixed: arr = [1, "two", true, {a: 3}];
@println => |mixed|

Runtime Value Variants#

Runtime also includes internal/native values:

  • Function, NativeFunction
  • Complex, Vector, Matrix runtime values
  • void

Type Methods#

Methods are called with value.method => |args|. Some methods return a new value, while others mutate the receiver (noted below).

In the signatures below, value means “an arbitrary runtime value” (it is not a declared type you can use in annotations).

Universal Methods#

These methods exist on every runtime value.

  • value.format => || -> string - Pretty-print a value (multi-line for arrays/objects) for debugging/logging.

format is intended for readable output. If you need a compact single-line representation, cast to string instead (.cast => |"string"|).

let a: arr = ["hi"];
let compact: string = a.cast => |"string"|;
let pretty: string = a.format => ||;
@println => |compact|
@println => |pretty|

String Methods#

String methods never mutate the original string (strings are values). Most return a new string.

  • s.length => || -> int - Character count.
  • s.toUpper => || -> string - Uppercase conversion.
  • s.toLower => || -> string - Lowercase conversion.
  • s.trim => || -> string - Remove leading and trailing whitespace.
  • s.split => |delimiter: string| -> arr - Split into an array of strings.
let s: string = "  Hello World  ";
let n: int = s.length => ||;
let upper: string = s.toUpper => ||;
let lower: string = s.toLower => ||;
let trimmed: string = s.trim => ||;
let parts: arr = s.split => |" "|;

Array Methods#

Array methods are a mix of read-only queries and mutating operations. Mutating methods change the array in-place.

  • a.length => || -> int - Number of elements.
  • a.first => || -> value - First element (runtime error if empty).
  • a.last => || -> value - Last element (runtime error if empty).
  • a.join => |sep: string| -> string - Join elements with a separator (elements are stringified).
  • a.remove => |value: value| -> value - Remove the first matching element (mutates, runtime error if not found).
  • a.push => |value: value| -> void - Append (mutates).
  • a.pop => || -> value - Remove last (mutates, runtime error if empty).
  • a.unshift => |value: value| -> void - Insert at front (mutates).
  • a.shift => || -> value - Remove first (mutates, runtime error if empty).
let nums: arr = [2, 4, 6];
let len: int = nums.length => ||;
let first: int = nums.first => ||;
let last: int = nums.last => ||;
nums.push => |8|
let removed: int = nums.pop => ||;
let front: int = nums.shift => ||;
nums.unshift => |1|
let removed_first_4: int = nums.remove => |4|;
let joined: string = nums.join => |"-"|;

Note: push, pop, shift, unshift, and remove mutate the array variable in-place, so call them on a named array (not a temporary expression).

Because arrays can contain mixed runtime values, you should annotate based on what you expect at runtime:

let a: arr = [1, "two"];
let v: int = a.first => ||; // OK (first is 1)
let w: int = a.last => ||;  // Type Error (last is "two")

Object Methods#

Objects map string keys to values. These methods help you inspect and safely read fields.

  • o.keys => || -> arr - Array of keys.
  • o.values => || -> arr - Array of values.
  • o.entries => || -> arr - Array of [key, value] pairs.
  • o.hasKey => |key: string| -> bool - Whether a key exists.
  • o.get => |key: string, default: value| -> value - Get a key, or return default if missing.
let user: obj = { name: "RAGE", score: 10 };
let keys: arr = user.keys => ||;
let values: arr = user.values => ||;
let entries: arr = user.entries => ||;
let has_name: bool = user.hasKey => |"name"|;
let title: string = user.get => |"title", "Untitled"|;

entries returns an array of [key, value] pairs.

Number Methods#

Number methods apply to int and float. Rounding methods return an int.

  • n.isOdd => || -> bool - True if the value is odd.
  • n.isEven => || -> bool - True if the value is even.
  • f.round => || -> int - Round to nearest integer.
  • f.floor => || -> int - Round down.
  • f.ceil => || -> int - Round up.
let a: int = 5;
let odd: bool = a.isOdd => ||;
let even: bool = a.isEven => ||;

let b: float = 7.9;
let r: int = b.round => ||;
let f: int = b.floor => ||;
let c: int = b.ceil => ||;

float also supports isOdd and isEven (based on the numeric value).

Casting#

All values support .cast => |"type"| for supported conversions.

let i: int = "42".cast => |"int"|;
let f: float = "3.14".cast => |"float"|;
let b: bool = "true".cast => |"bool"|;
let s: string = 99.cast => |"string"|;

Supported cast targets: "int", "float", "bool", "string".

Note: casting from string to a numeric/bool type only works for valid values (e.g. "10", "3.14", "true").