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.

Language overview

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.

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, and there is no official roadmap. It also seems to be less popular than Zig or Nim. 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 — an open source tool I'm building. Use it to embed live code snippets into your product docs, online course or blog.

★ Subscribe to keep up with new posts.