Yo Odin ยท Appendix A

Appendix A: Odin quick reference

A one-page cheat-sheet of the Odin used in this book. For the whole language, see the Overview and Karl Zylinski's odinbook.com.

Declarations

NAME :: value          // compile-time constant (also types & procedures)
x := value             // variable, type inferred
x: T = value           // variable, explicit type
x: T                   // variable, zero-initialised

Procedures

add :: proc(a, b: int) -> int { return a + b }
f   :: proc(x: int, y := 0) -> (ok: bool) { return true }   // default arg, named return
g   :: proc "c" () { }            // C ABI, no implicit context
h   :: proc "contextless" () { }  // no context

Types

i8 i16 i32 i64 int   u8 u16 u32 u64 uint   f32 f64   bool   string   rune
Vec2   :: [2]f32               // fixed array, behaves as a vector
Handle :: distinct u32         // fresh type, same representation
Size   :: enum { A, B, C }
Ship   :: struct { pos: Vec2, alive: bool }

Conversions are always explicit: f32(n), int(x), u32(h).

Arrays

a: [6]Bullet          // fixed: inline, no allocation
s := []int{1, 2, 3}   // slice: pointer + length
d: [dynamic]int       // dynamic: allocates (we avoid these in the game)
view := a[:]          // slice of a fixed array

Array programming ([2]f32)

a := Vec2{3, 4}
c := a + b * 2        // component-wise, scalar broadcast
a.x   a.y   a.yx      // components and swizzles

Control flow

for i in 0 ..< n { }       // half-open
for i in 0 ..= n { }       // inclusive
for x in xs { }            // by value
for &x in xs { x.f = 1 }   // by reference (writes stick)
if cond { } else { }
switch v { case .A: ; case: }   // no implicit fallthrough; `case:` is default
defer stmt                 // run at scope exit (LIFO)

Pointers

p: ^T = &x     // address-of
p^             // dereference (fields auto-deref: p.field)

Packages & imports

package main
import "core:math"          // standard library collection
import "core:math/rand"
import batch "../batch"      // relative import, aliased

WASM boundary

@(export)
batch_main :: proc "c" () {
	context = runtime.default_context()   // ALWAYS first line of an exported "c" proc
	// ...
}

foreign import app_env "app_env"
@(default_calling_convention = "contextless")
foreign app_env {
	set_fps :: proc(fps: f32) ---         // JS provides the body
}

Common core: calls used here

math.sin(x)  math.cos(x)  math.sqrt(x)  math.pow_f32(base, exp)  math.TAU
rand.float32()  rand.float32_range(lo, hi)  rand.reset(seed)  rand.int63()
strconv.write_int(buf[:], i64(n), 10)
os.read_entire_file_from_path(path, context.allocator)
net.listen_tcp(endpoint)  net.accept_tcp(sock)  net.recv_tcp(sock, buf)  net.send_tcp(sock, buf)