Walrus/Language

Variables

Local bindings, assignment, scope, and ownership-aware local rules in Walrus.

Updated April 17, 20263 min readWalrus / Variables

Walrus provides two ways to bind names to values: let and var. Both support optional type annotations.

let (Standard Binding)

let is the standard way to declare a local variable. In Walrus, local let bindings are mutable by default.

Walrus
let i = 0
i = i + 1 # This is allowed
i += 5    # This is also allowed

However, when used at the module scope, let defines a module constant that cannot be changed.

Walrus
module Config
let VERSION = "1.0.0" # Module-level constant

var (Captured Mutability)

In Walrus, var has a very specific purpose: it allows a variable to be mutated by a nested function (closure).

If you try to mutate a captured let variable inside a closure, you will get a compiler error. You must use var to indicate that the variable needs to be "shared" between the outer scope and the inner closure.

Walrus
fn counter() -> fn() -> int:
    var i = 0 # Must use 'var' for mutable capture

    fn next() -> int:
        i += 1 # Mutates 'i' in the outer scope
        return i

    return next

Type Annotations

While Walrus has strong type inference, you can explicitly annotate any variable:

Walrus
let score: int = 100
let name: string = "Walrus"
let view: ref string = name

Scope and Lifetime

  • Lexical Scope: Variables are only available within the block (and nested blocks) where they are defined.
  • Move on Move: When an owned value (like a string or array) is assigned to a new variable, the old variable becomes invalid.
  • Shadowing: Declaring a new variable with the same name as an existing one in a nested block is permitted and will "shadow" the outer variable.