Skip to content

Variables & Mutability

In Wysna, variables are immutable by default. This design choice prevents unexpected state mutations across scopes and makes programs easier to reason about and optimize.

When you declare a variable using let, its value cannot be modified after initialization:

fn main() -> unit {
let port = 8080
print("Listening on port:", port)
# The following will trigger a compile-time error:
# port = 9000 # Error: Cannot reassign immutable variable `port`
}

The compiler enforces this check during High-Level IR (HIR) verification.


When a variable needs to change over time, declare it explicitly using let mut:

fn main() -> unit {
let mut counter = 0
print("Initial:", counter)
counter = counter + 1
counter = counter + 5
print("Updated:", counter)
}

Notice that mutability is a property of the binding, not an inherent property of the data type itself.


Wysna provides robust local type inference. You do not have to write type annotations when the type is obvious from the right-hand expression:

fn main() -> unit {
# Inferred types
let a = 42 # inferred as int
let b = 3.14159 # inferred as float
let c = "Wysna" # inferred as str
let d = true # inferred as bool
# Explicit type annotations
let count: int = 100
let ratio: float = 0.75
let title: str = "Systems Engineering"
}

Best Practice: While local variables can safely rely on inference, function parameters and return types must always have explicit type annotations. This guarantees that modules have clear, self-documenting contracts.