Flash tutorial · 4 / 12
4. 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.
// 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.
// 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.
// 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. Runningflashc fmtrewrites an untypedconst name = exprinto thename := exprshort-hand automatically, so formatted Flash uses:=consistently. Aconstthat 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.
// 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 =:
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.
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
undefinedbefore 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 =:
// 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):
// 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(…).