Odin't Know That · Appendix A

Appendix A: Odin quick reference

A one-page reminder of the Odin features this book uses. For the whole language, see *Understanding the Odin Programming Language* and the official overview.

Declarations

NAME :: value          // compile-time constant (also procs and types)
x := value             // variable, type inferred
y: f32 = value         // variable, explicit type

Procedures

add :: proc(a, b: int) -> int { return a + b }
pair :: proc() -> (a: int, ok: bool) { return 42, true }   // multiple returns
f :: proc(protected := false) {}                            // default argument

Primitive types

bool; i8 i16 i32 i64, u8 u16 u32 u64; int uint (pointer-sized); f32 f64; rune, string, cstring, rawptr. No implicit conversion; convert explicitly: f32(n), int(x). C interop types come from core:c: c.int, c.uint.

Untyped-constant gotcha: a float constant assigned with := defaults to f64. Pin the type when mixing with f32: air: f32 = 2 * A / B.

Structs and enums

Player :: struct { pos: Vec2, on_ground: bool }   // every field has a zero value
p := Player{pos = {0, 400}}                        // unset fields are zero

Kind :: enum u8 { Rock, Boulder, Stump }           // Rock = 0, ...
Defs := [Kind]int { .Rock = 1, .Boulder = 2, .Stump = 3 }  // enumerated array (must be complete)

distinct T makes a fresh type with T's representation (raylib: Color :: distinct [4]u8).

Arrays

fixed:   [64]Obstacle    // fixed-size, inline, no allocation
slice:   []u8            // (ptr, len) view; buf[:] makes one
dynamic: [dynamic]int    // growable, allocates

Array programming on [N]f32: a + b, a * 2 (broadcast), a * b (component-wise), a.x, a.yx (swizzle). Vec2 :: rl.Vector2 is [2]f32.

Pointers

p := &x        // address-of
p^             // dereference
for &o in xs { o.field = 1 }   // &o mutates the element in place; without &, you edit a copy

Control flow

if cond { } else { }
if !ok do return                 // single-statement form
switch v { case .A: ; case .B: } // no fallthrough; enum switches checked for completeness
switch { case x > 0: ; case: }   // no-operand switch = if/else-if ladder
for i in 0 ..< n { }             // half-open range (excludes n)
for i in 0 ..= n { }             // closed range (includes n)
for cond { }                     // while-loop
for { }                          // infinite
defer stmt                       // run stmt at scope exit (reverse order)

Builtins (no import): min max clamp abs len.

context and calling conventions

context.random_generator = rand.default_random_generator(&state)  // set for this scope
context.allocator = ...

f :: proc "c" (n: c.uint) {          // C calling convention (e.g. a raylib callback)
	context = runtime.default_context()   // re-establish a context at the boundary
}

C interop essentials

  • cstring: zero-terminated. Literals convert for free; dynamic text via fmt.ctprintf (temp allocator, per-frame, no leak). Never keep a temp cstring past the frame.
  • Shared value types with raylib: Vector2 ([2]f32), Rectangle (struct), Color (distinct [4]u8).
  • rawptr(raw_data(slice)) to pass a slice's memory to a C API; ([^]i16)(ptr) to view a raw pointer as a multi-pointer.

Standard library used

core:math (sin cos exp floor, PI TAU) · core:math/rand (create_u64, default_random_generator, float32, float32_range, int_max) · core:strconv (parse_int, write_int) · core:os (read_entire_file_from_path, write_entire_file) · core:fmt (ctprintf, println) · core:c (c.int, c.uint) · base:runtime (default_context).