Trying Odin (with a playground)
In my recent search for a "better C" alternative, I've looked at C++, D, Rust, Nim, Hare, Odin, and Zig. At first glance, Odin and Zig seem to be exactly what I'm looking for. C++, D, Rust and Nim are bloated with features, while Hare is too bare-bones even for me.
Why do I need a better C when I have Go, you may ask. Well, Go is great at everything except C interop (which I sometimes need). It also has GC (which I sometimes don't need).
I think of Go as "better Java". It'd be nice to have better C, too.
I'll leave Zig for later and explore Odin for now.
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.
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.
Trying Odin
The easiest way to get a taste of Odin is the playground I made (it powers the examples in this article).
If you prefer local setup, the official site has a decent "Getting Started" guide. There are binaries for Windows, Linux and macOS, but unfortunately only for amd64 (x86_64).
If you have an arm64 Mac, you can use a Docker image (courtesy of Yeongju Kang with minor modifications by me).
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.
Current status
Odin is pre-1.0. Sadly, it does not even have a 1.0 roadmap. It also seems to be less popular than Zig or Nim, probably on par with Hare.
However, Odin is actively used in production by the company it's creator works for.
So I hope it has a bright future!
──
Interactive examples in this post are powered by codapi — the platform I'm building. Use it to embed code playgrounds into your online course, documentation, or blog.
Subscribe to keep up with new posts.