ajhahn.de
← Flash
Markdown 122 lines
# Flash Variables & Constants

In Flash, values are declared with explicit mutability control. You can declare values using `var`, `const`, or the short-hand initialization operator `:=`.

---

## 1. Variable Declarations (`var`)
Variables declared with `var` are **mutable**; their values can be modified after initialization.
* **With Explicit Type:** Specify the type between the name and the `=` operator.
* **With Inferred Type:** Omit the type, and the compiler will infer it from the right-hand side expression.

```flash
// Explicit type
var count i32 = 0
count = count + 1 // OK

// Inferred type
var factor = 2.5
factor = factor * 2.0 // OK
```

---

## 2. Constant Declarations (`const`)
Constants declared with `const` are **immutable**. Once initialized, their value cannot be changed.
* Like variables, you can either provide an explicit type or let the compiler infer it.

```flash
// Explicit type
const MAX_BUFFER usize = 1024

// Inferred type
const greeting = "Hello, Flash!\n"

// MAX_BUFFER = 512 // Compiler error downstream!
```

---

## 3. Short-hand Declaration (`:=`)
For quick bindings where you want the type to be inferred, Flash provides the `:=` short-hand syntax.

**Important:** Short-hand declarations using `:=` are **immutable** (constant) by default. They are a convenient syntactic sugar for `const name = expression`.

```flash
// Syntax: name := expression (equivalent to const name = expression)
msg := "hello\n"   // Inferred as constant string slice []const u8
// msg = "world"   // Compiler error downstream!
```

> [!NOTE]
> `:=` is the **canonical** spelling for an untyped immutable local. Running `flashc fmt` rewrites an untyped `const name = expr` into the `name := expr` short-hand automatically, so formatted Flash uses `:=` consistently. A `const` that carries an explicit type — `const MAX usize = 1024` — is left exactly as written.

---

## 4. Destructuring

A tuple value — most often a multi-value return (see Chapter 5) — unpacks into several names in one statement. One keyword rules all the names: `:=` declares every target immutably, `var … =` declares every target mutably.

```flash
// Both names declared immutably
q, r := divmod(7, 2)

// Both names declared mutably
var x, y = pair()

// _ skips a position you do not need
tok, _ := next()
```

Existing lvalues — including member and index targets — take a **destructuring assignment** with plain `=`:

```flash
x, arr[0] = pair()
```

A few rules keep the form unambiguous: a `:=` target must be a plain name (assign to members or indices with `=`), a compound operator like `+=` cannot destructure, and a destructure that discards every position is written `_ = expr` instead.

---

## 5. Undefined Values
In low-level systems programming, you often want to allocate space for a variable without spending CPU cycles initializing it. Flash allows you to initialize a variable as `undefined`.

```flash
use flibc

export fn main(_ usize, _ argv) noreturn {
    // Allocate 512 bytes on the stack without initializing
    var buffer [512]u8 = undefined
    
    // Fill it via a read syscall
    _ = flibc.sys.read(0, &buffer, buffer.len)
    
    flibc.exit()
}
```

> [!WARNING]
> Accessing a variable initialized to `undefined` before writing to it results in undefined behavior. Use with care.

---

## 6. Alignment & Section Placement (`align`, `linksection`)

A binding can pin the alignment of its storage with `align(N)`, written between the type and the `=`:

```flash
// A page-aligned buffer — valid at file scope and inside functions
var pool [4096]u8 align(4096) = undefined
```

The form works on locals and on file-scope bindings alike, `extern var` included (the alignment becomes part of the symbol's contract).

A file-scope binding can also name the **linker section** its symbol lands in with `linksection("…")`, in the same slot (after any `align`):

```flash
// Pin read-only data where the linker script expects it
const PAD [4096]u8 linksection(".rodata") = [_]u8{0} ** 4096
```

Two boundaries: an `extern var` cannot carry a `linksection` (the defining object owns the section), and a local binding cannot either (a stack slot lives in no section). Functions take the attribute too, between the parameter list and any `callconv(…)`.