Variables & Types
Variables are declared with let. Types are optional — you can add them for safety or leave them out for flexibility.
Variables
Use let to declare a variable. Reassign it with plain = — no let again:
let name = "Sergio"
let count = 20
let active = true
count = count + 1 // reassignment
name = "Ana" // also fineVariables declared inside a block { } are invisible outside it. You can still mutate variables from an outer scope:
let total = 0
{
let local = 42 // only lives inside this block
total = local // outer variable — allowed
}
out total // → 42
// out local ❌ ERROR: Variable not found: localConstants
Use const for values that should never change. Any attempt to reassign is an error:
const PI = 3.14159
const MAX = 100
PI = 3.0 // ❌ ERROR: Cannot reassign const 'PI'Types
Serez Code has five primitive types and several compound types:
| Type | Example | What it is |
|---|---|---|
int | 42, -7, 0 | 64-bit whole number |
decimal | 3.14, 0.5, 2.0 | 64-bit floating point |
dec | 12.50m, 5m, 1e-7m | Exact base-10 decimal (28–29 digits) |
bool | true, false | Boolean value |
string | "hello", r"raw {x}" | UTF-8 text (interpolated or raw) |
null | null | Absence of a value |
any | — | Accepts any value, skips type checks |
void | — | Return type for functions that return nothing |
Type annotations
Add types to function parameters and return values. When present, they're enforced at every call:
fn int add(int a, int b) {
return a + b
}
add(1, 2) // ✅
add(1, "hello") // ❌ TYPE ERROR: Parameter 'b' expected 'int' but received 'string'Skip annotations when you want flexibility — the parameter accepts any value:
fn multiply(a, b) {
return a * b
}
multiply(3, 4) // ✅
multiply(2.5, 4.0) // ✅Nullable types
Append ? to any type to allow null as a valid value:
fn int? findIndex(string target, [string] list) {
for (let i = 0; i < list.length; i++) {
if (list[i] == target) { return i }
}
return null
}
let idx = findIndex("Ana", ["Bob", "Ana", "Lee"])
if (idx != null) {
out "Found at index {idx}" // → Found at index 1
} else {
out "Not found"
}Exact decimals (dec)
decimal is f64 — fast, but binary, so 0.1 + 0.2 != 0.3. For money and anything that can't tolerate rounding drift, use dec: an exact base-10 decimal written with the m suffix.
out 0.1 + 0.2 == 0.3 // false (f64)
out 0.1m + 0.2m == 0.3m // true (exact)
let price = 12.50m // inferred dec; scale preserved → "12.50"
let total = price * (1m + 0.21m)
out total // 15.1250
// rounding is explicit (COBOL ROUNDED == "half-up")
out (1000.00m * 0.21m).setScale(2, "half-up") // 210.00
out Dec.fromInt(1250, 2) // 12.50int mixes in exactly; mixing dec with decimal (f64) is a type error — convert with d.toDecimal() / Dec.parse. Methods: round setScale truncate scale abs floor ceil isZero sign min max toInt toDecimal toString; namespace Dec.parse / fromInt / MAX / MIN / MAX_SCALE.
String interpolation
Embed any expression directly inside a string with {}:
let name = "Sergio"
let age = 28
out "My name is {name} and I'm {age} years old."
let result = add(3, 7)
out "3 + 7 = {result}"
// Works with method calls too
out "Upper: {name.toUpperCase()}" // → Upper: SERGIO\{ / \} for literal braces inside a string ("Empty dict: \{\}"), or a raw string to disable interpolation entirely.Raw strings (r"…")
A r"…" string disables interpolation and escape processing — braces and backslashes are literal. Ideal for literal braces, Windows paths and regexes. It cannot contain a ".
let x = 5
out "value is {x}" // value is 5 (interpolated)
out r"value is {x}" // value is {x} (raw)
out r"C:\temp\new" // C:\temp\new (no escapes)
out r"\d+\.\d{2}" // \d+\.\d{2} (regex literal)Operators
Arithmetic
out 10 + 3 // → 13
out 10 - 3 // → 7
out 10 * 3 // → 30
out 10 / 3 // → 3 (integer division, truncates)
out 10 % 3 // → 1 (remainder)
out 2 ** 10 // → 1024 (power)
// int and decimal mix freely
out 1 + 0.5 // → 1.5Comparison & logical
out 5 > 3 // → true
out 5 == 5 // → true
out 5 != 3 // → true
out true && false // → false (AND)
out true || false // → true (OR)
out !true // → false (NOT)Compound assignment
let n = 10
n += 5 // n = 15
n -= 3 // n = 12
n *= 2 // n = 24
n /= 4 // n = 6
n++ // n = 7
n-- // n = 6Ternary
let x = 10
let label = x > 5 ? "big" : "small"
out label // → big
// Chain them
let n = 2
let name = n == 1 ? "one" : n == 2 ? "two" : "other"
out name // → twoNull coalescing
let value = null
out value ?? "default" // → default
let maybeNum = findIndex("Ana", names)
let safe = maybeNum ?? -1 // -1 if not foundType check
out 42 is int // → true
out "hi" is int // → false
out 3.14 is decimal // → true
// Useful for functions that accept any
fn string describe(any v) {
if (v is int) { return "int: {v}" }
if (v is string) { return "string: {v}" }
return "other"
}Comments
// Single-line comment
/* Multi-line
comment */
let x = /* inline */ 42Type conversions
// String → int
out parseInt("42") // → 42
out parseInt(3.99) // → 3 (truncates)
// String → decimal
out parseDecimal("3.14") // → 3.14
out parseDecimal(5) // → 5.0
// Any type → string
out 42.toString() // → "42"
out true.toString() // → "true"
// Read from stdin
let input = readLine("Enter a number: ")
let num = parseInt(input)