Markdown 133 lines
# Chapter 5: Data Types & Pointers
Flash is a statically typed programming language. This means that variables must have a defined type, which is checked at compile-time.
---
## 1. Primitive Types
Flash contains a standard set of systems-level primitive types:
| Type | Size / Category | Description | Example |
| :--- | :--- | :--- | :--- |
| **`u8`** | 8-bit | Unsigned integer (byte) | `var value u8 = 255` |
| **`u32`** | 32-bit | Unsigned integer | `var value u32 = 42000` |
| **`i32`** | 32-bit | Signed integer | `var value i32 = -15` |
| **`usize`** | Pointer size | Unsigned size type (size of memory address) | `var len usize = 512` |
| **`bool`** | Boolean | Store either `true` or `false` | `var ok bool = true` |
| **`void`** | Special | Empty or no value | *Used for functions returning nothing* |
| **`noreturn`** | Special | Indication that a function never returns | *Used for main exit calls* |
---
## 2. Pointer Types
Pointers store memory addresses and allow direct access to memory. In Flash, pointers have distinct safety and usage categories:
### Single-item Pointers (`*T` / `*mut T`)
Points to exactly one value of type `T` in memory.
* **`*T`**: Pointer to a constant (immutable) value of type `T`. This is the default.
* **`*mut T`**: Pointer to a mutable value of type `T`.
```flash
var value i32 = 42
// Create a mutable pointer to value
const ptr *mut i32 = &value
// Dereference the pointer to read/write the value
ptr.* = 100
```
### Many-item Pointers (`[*]T` / `[*]mut T`)
Points to an array of unknown size in memory. No bounds checking is performed.
* **`[*]T`**: Points to a read-only sequence of items.
* **`[*]mut T`**: Points to a mutable sequence of items.
### Sentinel-terminated Pointers (`[*:s]T`)
A many-item pointer terminated by a specific sentinel value `s`.
* Most commonly used for C-style strings: `[*:0]u8` (null-terminated string).
### Alignment-Qualified Pointers (`*align(N) T`)
A pointer or slice type can carry an explicit alignment, written directly after the prefix and before any `mut` / `volatile`:
```flash
const page []align(16) u8 = getBuffer()
var reg *align(4) mut volatile u32 = mapRegister()
```
The alignment is part of the pointer type's identity — `*align(4) u32` and `*u32` are distinct types. Sentinel forms compose too: `[*:0]align(2) mut u8`.
### Built-in Pointer Aliases
To make systems programming and C interoperability cleaner, Flash provides two built-in pointer aliases:
* **`cstr`** — translates to `[*:0]const u8` (a null-terminated constant byte pointer, representing a C string).
* **`argv`** — translates to `[*]const ?[*:0]const u8` (an array of null-terminated C strings, representing command line arguments).
---
## 3. Pointer Dereferencing (`p.*`)
To access or modify the value at a pointer's memory address, use the **`.*`** suffix notation.
```flash
var x u32 = 10
var px *mut u32 = &x
// Access and modify via dereference
px.* = 20 // Now x is 20
```
> [!NOTE]
> When accessing fields on pointers to structs, dereferencing is done automatically by the compiler. You can write `ptr.field` directly instead of `ptr.*.field`.
---
## 4. Type Aliases
A type is a compile-time value, so naming one is an ordinary `const` — and composite types are expressions, so no wrapper is needed:
```flash
const Byte = u8 // a primitive alias
const Bytes = []u8 // a slice alias
const MaybeLen = ?usize // an optional alias
const Handler = *fn(u8) u8 // a function-pointer alias
```
Aliases work at file scope and inside functions, and a composite type can sit directly in a generic argument (`List([]u8)`). One boundary: the infix error union `E!T` cannot be the value of an alias directly — name the error set and compose it at the use site instead.
---
## 5. Tuple Types & Multiple Return Values
A parenthesized list of **two or more** types is a tuple type, spellable wherever a type is — a return, a parameter, an alias, or nested as an element:
```flash
const Pair = (u8, bool)
// A function returning two values: the quotient and the remainder
fn divmod(a u32, b u32) (u32, u32) {
return a / b, a % b
}
```
A `return` heading a statement takes a comma-separated value list — Go's multi-return idiom. The tuple *value* literal stays `.{ … }`, and elements read by index:
```flash
t := .{ 42, true }
n := t[0]
```
The cleanest way to consume a multi-value return is a destructuring bind (`q, r := divmod(7, 2)` — see Chapter 4). A one-element `(T)` stays plain grouping, and a parenthesized *value* list like `(1, 2)` is rejected with a hint steering to `.{ … }`.
---
## 6. Function Types & Calling Conventions (`callconv`)
A function *type* — `fn(P, …) R`, usually behind a pointer (`*fn(u8) u8`) — can name an explicit calling convention between its parameter list and return type:
```flash
// An optional C-ABI function pointer: the v-table field shape
const Handler = ?*fn(u32, *mut [512]u8) callconv(.c) i32
```
This is the form a driver table's entries take when they cross an ABI boundary. The convention sits exactly where a function *declaration* puts it, and it is part of the type's identity at compile time — `fn() callconv(.c)` and `fn()` are distinct types.