Variables
Almide has two ways to bind values: let for immutable bindings and var for mutable bindings.
let (immutable)
Section titled “let (immutable)”let creates an immutable binding. Once bound, the value cannot be changed:
let name = "Alice"let age = 30let active = trueAttempting to reassign a let binding is a compile error:
let x = 1x = 2 // Compile error: cannot reassign immutable bindingvar (mutable)
Section titled “var (mutable)”var creates a mutable binding that can be reassigned:
var count = 0count = count + 1count = count + 1println(int.to_string(count)) // "2"Mutable bindings also enable in-place operations on collections:
var items = ["a", "b", "c"]items[0] = "A" // index writelist.push(items, "d") // push to end
var scores: Map[String, Int] = [:]scores["alice"] = 100 // map writeUse var sparingly. Prefer let unless mutation is necessary.
Type annotations
Section titled “Type annotations”Type annotations are optional when the type can be inferred:
let x = 42 // inferred as Intlet y: Int = 42 // explicit annotationAnnotations are required when the type cannot be inferred, such as empty collections:
let xs: List[String] = []let m: Map[String, Int] = [:]The annotation syntax is name: Type:
let pair: (Int, String) = (1, "one")let f: Fn(Int) -> Int = (x) => x + 1Destructuring
Section titled “Destructuring”Record destructuring extracts fields into individual bindings:
type User = { name: String, age: Int }
let user = { name: "Alice", age: 30 }let { name, age } = userprintln(name) // "Alice"Destructuring rules:
- Only one level deep (no nested destructuring)
- No renaming (field names become variable names)
letonly (novardestructuring)
Top-level let (constants)
Section titled “Top-level let (constants)”let at the top level creates module-scope constants:
let PI = 3.14159265358979323846let MAX_RETRIES = 3let GREETING = "Hello, world"By convention, top-level constants use UPPER_CASE names. They are evaluated at compile time when possible.
Shadowing
Section titled “Shadowing”A new let binding can shadow an existing binding in the same scope:
let x = 1let x = x + 1 // shadows the previous xprintln(int.to_string(x)) // "2"Shadowing creates a new binding rather than mutating the existing one.
Discard with _
Section titled “Discard with _”Use _ to discard a value you don’t need:
let _ = some_function() // call for side effect, discard resultIn for loops, _ ignores the loop variable:
for _ in 0..5 { println("tick")}In tuple destructuring within for:
for (_, v) in map.entries(config) { println(v)}Next steps
Section titled “Next steps”- Types & Values — the full type system
- Functions — defining and calling functions
- Control Flow — if, for, while, guard