Try / Odin in Y minutes
Odin is a general-purpose programming language with distinct typing, designed for high performance, modern systems, and data-oriented programming. Some people refer to Odin as "better C".
Odin has a unique set of characteristics:
- Simple language design without bells and whistles.
- Manual memory management with custom allocators.
- Well-thought standard library.
- Concise and calm syntax.
✨ This guide needs some love
The guide is too brief. It would be great to take the official Odin overview and make it interactive. If you'd like to help — please contribute!
Some examples
A classic "hello world":
package main
import "core:fmt"
main :: proc() {
fmt.println("Hellope!")
// Hellope!
}
Dynamic arrays and sorting:
package main
import "core:fmt"
import "core:slice"
main :: proc() {
list := [dynamic]int{11, 7, 42}
defer delete(list)
append(&list, 2, 54)
slice.sort(list[:])
fmt.println(list)
// [2, 7, 11, 42, 54]
}
Memory management in Odin is manual, so allocated memory must be explicitly freed. There are two built-in allocators (a heap allocator and a growing arena based allocator), but the language supports custom allocators:
// tracking allocator for debugging
track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator)
// context is an implicit variable
// available in every scope
context.allocator = mem.tracking_allocator(&track)
// we can use a custom allocator at any level,
// even at individual statements
list := make([]int, 6, context.allocator)
Structs, procedures and iteration (I'll skip the "package" stuff from now on):
Person :: struct {
name: string,
age: int,
}
person_to_str :: proc(p: Person) -> string {
return fmt.tprintf("%v - %v", p.name, p.age)
}
people := []Person{
Person{"Alice", 25},
Person{"Bob", 24},
Person{"Cindy", 26},
}
for p, idx in people {
fmt.println(idx, person_to_str(p))
}
// 0 Alice - 25
// 1 Bob - 24
// 2 Cindy - 26
There are no functions or struct methods, only procedures.
Pointers are declared with a leading caret, and dereferenced with a trailing caret:
val := "Hellope!"
ptr: ^string
ptr = &val
fmt.println(ptr^)
// Hellope!
A bit unusual, but logical.
Errors are just values:
Error :: enum {
None,
Insufficient_Funds,
}
withdraw :: proc(balance, amount: int) -> (int, Error) {
if amount > balance {
return balance, .Insufficient_Funds
}
return balance - amount, .None
}
balance, err := withdraw(42, 1000)
if err != nil {
fmt.println(err)
}
// Insufficient_Funds
There is also a shortcut for the dreaded if err != nil return
:
balance := withdraw(42, 1000) or_return
Generics (aka parametric polymorphism):
Pair :: struct($T: typeid) {
first: T,
second: T
}
pair_to_str :: proc(p: $T/Pair) -> string {
return fmt.tprintf("%v-%v", p.first, p.second)
}
p1 := Pair(int){1, 2}
p2 := Pair(string){"one", "two"}
fmt.println(pair_to_str(p1))
// 1-2
fmt.println(pair_to_str(p2))
// one-two
Here pair_to_str
only allows types that are specializations of the Pair
type.
Specialization
Although Odin is a general-purpose language, it leans slightly towards game and visual effects programming. This is probably due to the fact that the language creator (Ginger Bill) is a physicist working in a visual effects company.
Odin supports a native matrix
type and matrix operations, and has various SIMD/SIMT-related programming features (of which I don't know anything about, so better consult the doc for those).
As far as I can tell, a significant number of programmers using Odin are game developers.
Further reading
See the Odin documentation for a detailed overview, frequently asked questions, and language specification.
Anton Zhiyanov · original · CC-BY-SA-4.0 · 2023-07-31
Anton Zhiyanov