___________ __________ _____ ________ ________ .____ ___________ \_ _____/ \______ \ / _ \ / _____/ / _____/ | | \_ _____/ | __) | _/ / /_\ \ / \ ___ / \ ___ | | | __)_ | \ | | \ / | \ \ \_\ \ \ \_\ \ | |___ | \ \___ / |____|_ / \____|__ / \______ / \______ / |_______ \ /_______ / \/ \/ \/ \/ \/ \/ \/

Odin Quickstart Reference

← Back to quick reference

← Home


Quick reference guide for Odin. Essential syntax, types, control flow, and common patterns for the Odin programming language.


Hello World

package main

import "core:fmt"

main :: proc() {
    fmt.println("Hello, World!")  // Odin keeps it clean and readable.
}

Variables

x: int = 42
name: string = "Alice"
flag: bool = true
pi: f64 = 3.14

// Type inference with :=
y := 100              // Compiler infers int
text := "Hello"       // Compiler infers string

// Multiple declarations
a, b, c: int = 1, 2, 3

Control Flow

If/Else

if x > 10 {
    fmt.println("x is big")
} else {
    fmt.println("x is small")
}

if x > 10 {
    fmt.println("big")
} else if x > 5 {
    fmt.println("medium")
} else {
    fmt.println("small")
}

// If as expression
result := "big" if x > 10 else "small"

For Loops

for i in 0..5 {          // 0 to 4, exclusive
    fmt.println(i)
}

for i in 0..=5 {        // 0 to 5, inclusive
    fmt.println(i)
}

nums := []int{1, 2, 3}
for n in nums {
    fmt.println(n)
}

for n, i in nums {      // Value and index
    fmt.printf("%d: %d\n", i, n)
}

// Traditional C-style
for i := 0; i < 5; i += 1 {
    fmt.println(i)
}

While Loops

y := 10
for y > 0 {
    y -= 1
    fmt.println(y)
}

// Infinite loop
for {
    if y <= 0 {
        break
    }
    y -= 1
}

Functions

add := fn(a: int, b: int) -> int {
    return a + b
}

fmt.println(add(2, 3))

// Named function
add :: proc(a: int, b: int) -> int {
    return a + b
}

// Multiple return values
divide :: proc(a: f64, b: f64) -> (f64, bool) {
    if b == 0 {
        return 0, false
    }
    return a / b, true
}

result, ok := divide(10.0, 2.0)
if ok {
    fmt.println(result)
}

// Procedures (no return value)
greet :: proc(name: string) {
    fmt.printf("Hello, %s!\n", name)
}

Arrays / Slices

Slices

nums: []int = [1, 2, 3]  // Slice literal, mutable and resizable
for n in nums {
    fmt.println(n)
}

// Append to slice
append(&nums, 4)
append(&nums, 5, 6)

// Length and capacity
len(nums)               // Current length
cap(nums)               // Capacity

// Make slice with capacity
nums := make([]int, 0, 10)  // Length 0, capacity 10

Arrays

arr: [3]int = {1, 2, 3}  // Fixed-size array
arr := [3]int{1, 2, 3}   // Shorthand

// Array size inference
arr := [?]int{1, 2, 3}   // Compiler infers size 3

Maps

import "core:map"

person := make(map[string]string)
map.set(&person, "name", "Alice")
map.set(&person, "age", "30")

name, found := map.get(&person, "name")
if found {
    fmt.println(name)
}

// Map literal
person := map[string]string{
    "name" = "Alice",
    "age"  = "30",
}

Strings

text := "Hello, World!"
text := `Multiline
string
literal`

// String operations
len(text)                // Length in bytes
fmt.printf("%s\n", text) // Print formatted

// String concatenation
greeting := "Hello, " + name

// String formatting
name := "Alice"
greeting := fmt.tprintf("Hello, %s!", name)

Structs

Person :: struct {
    name: string,
    age:  int,
}

person := Person{
    name = "Alice",
    age  = 30,
}

fmt.printf("%s is %d\n", person.name, person.age)

// Methods
Person :: struct {
    name: string,
    age:  int,
}

greet :: proc(p: Person) {
    fmt.printf("Hello, I'm %s\n", p.name)
}

person := Person{name = "Alice", age = 30}
greet(person)

Enums

Direction :: enum {
    Up,
    Down,
    Left,
    Right,
}

dir := Direction.Up

switch dir {
case .Up:
    fmt.println("Going up")
case .Down:
    fmt.println("Going down")
case .Left:
    fmt.println("Going left")
case .Right:
    fmt.println("Going right")
}

Unions

Value :: union {
    int,
    f64,
    string,
}

v: Value = 42
v = 3.14
v = "hello"

switch v in v {
case int:
    fmt.printf("Integer: %d\n", v)
case f64:
    fmt.printf("Float: %f\n", v)
case string:
    fmt.printf("String: %s\n", v)
}

Error Handling

import "core:fmt"

// Using optional types
divide :: proc(a: f64, b: f64) -> (result: f64, ok: bool) {
    if b == 0 {
        return 0, false
    }
    return a / b, true
}

result, ok := divide(10.0, 2.0)
if ok {
    fmt.printf("Result: %f\n", result)
} else {
    fmt.println("Division by zero")
}

// Using error types
Error :: enum {
    None,
    Division_By_Zero,
    Invalid_Input,
}

divide :: proc(a: f64, b: f64) -> (f64, Error) {
    if b == 0 {
        return 0, .Division_By_Zero
    }
    return a / b, .None
}

File Operations

import "core:os"
import "core:fmt"

// Reading
data, ok := os.read_entire_file("file.txt")
if ok {
    fmt.println(string(data))
}

// Writing
content := "Hello, World!"
os.write_entire_file("file.txt", transmute([]u8)content)

Memory Management

import "core:mem"

// Allocators
allocator := context.allocator

// Allocate memory
ptr := new(int)
ptr^ = 42

// Free memory
free(ptr)

// Using different allocators
temp_allocator := mem.temp_allocator()

Tips

  • Odin is strongly typed; type declarations are explicit.
  • Loops often use ranges like 0..5 (exclusive of 5); use 0..=5 for inclusive.
  • fmt.scanf or read_string can handle user input:
    import "core:fmt"
    import "core:os"
    
    input: [256]u8
    n, _ := os.read(os.stdin, input[:])
    text := string(input[:n])
  • Slices ([]Type) are dynamic arrays, arrays ([N]Type) are fixed-size.
  • Functions are first-class and can be assigned to variables.
  • Use := for type inference, : for explicit typing.
  • Procedures (proc) are functions; use fn for function values.
  • Multiple return values are common; use tuples or named returns.
  • Use ^ to dereference pointers, & to take addresses.
  • Odin uses explicit memory management; understand allocators for advanced usage.
  • Struct literals use = for field assignment: Person{name = "Alice"}.
  • Use switch for pattern matching on enums and unions.
  • Import packages with import "package:name"; core library uses "core:" prefix.