# Variables, mutability, and scope

```cplus
let x: i32 = 5;             // immutable
let y = 5;                  // inferred as i32
let mut z: i32 = 0;         // mutable
z = 7;

let w: i32;                 // uninitialised
w = 12;                     // first write counts as init; later writes need `mut`
```

Mutability is opt-in: a plain `let` is immutable, and you reach for `mut` only when you need it. If you forget to initialise on a path, the compiler tells you (**E0345**). If you reassign without `mut`, it tells you. Shadowing is allowed: a new `let` with the same name introduces a new binding.

Scope is curly-brace lexical. A binding lives until its enclosing block exits, at which point its [`Drop`](/docs/drop-and-defer) runs.

## Module-scope `const` and `static`

`let` lives inside a function. For named values shared across functions, or for the C-style "static storage" pattern where a value lives for the whole program, use `const` or `static` at module scope.

```cplus
// `const` — a typed alias for a literal. No storage, no address.
// Every use site is rewritten to the literal at compile time.
const HEADER_BYTES: usize = 176;
const PI: f32 = 3.14159f32;

// `static` — a global with a real address, initialised once before main.
// The immutable form lives in .rodata.
static IMMUTABLE_OFFSET: i32 = 50;

// `static mut` — mutable global. Reads and writes require `unsafe`,
// since the borrow checker can't prove absence of data races on it.
static mut COUNTER: i32 = 0;

fn bump(by: i32) {
    unsafe { COUNTER = COUNTER + by; }
    return;
}
```

Three rules:

1. **The initialiser must be a literal** (or `#zero::[T]()`): integer, float, bool, string, a unary-negated numeric literal, or explicit zero-fill. Arithmetic such as `const N: i32 = 1 + 2;` is rejected, as is referring to another const. A `static` additionally accepts an array literal or fill (`static Z: [u8; 64] = [0u8; 64];`) and a non-generic struct literal (`static S: Point = Point { x: 1, y: 2 };`), composing recursively, since it becomes an LLVM constant aggregate. `const` stays literal-only because it is inlined at use sites.
2. **A type annotation is required**; there is no inference. `const FOO = 5;` is rejected.
3. **`static mut` reads and writes need `unsafe`**. Writing to an immutable `static` is **E0305**.

| You want | Use |
|---|---|
| A named literal referenced at multiple sites | `const` |
| A fixed offset or lookup table read at runtime | `static` |
| A mutable counter, RNG state, or lazy cache | `static mut` |
