Язык Odin

Давно подыскиваю для себя альтернативу языку C. Посмотрел на днях Rust, Nim, Zig, Hare и Odin. На первый взгляд, Odin — именно то что нужно. Единственный из всех не перегружен фичами (кроме Hare — но тот, напротив, слишком минималистичный даже для меня).

Может возникнуть вопрос: зачем мне вообще альтернатива C, если у меня уже есть Go? Go действительно прекрасен всем, кроме взаимодействия с C (которое мне иногда нужно). Кроме того, в нем есть сборщик мусора (который мне иногда не нужен).

Для меня Go — это замена Java. А хотелось бы еще замену C.

У Odin уникальный набор качеств:

  • Простой язык без лишних прибамбасов.
  • Ручное управление памятью с настраиваемыми аллокаторами.
  • Продуманная стандартная библиотека.
  • Лаконичный и спокойный синтаксис.

Тур по языку

Классический «привет, мир»:

package main

import "core:fmt"

main :: proc() {
    fmt.println("Hellope!")
    // Hellope!
}

Динамические массивы и сортировка:

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]
}

Управление памятью ручное, так что выделенную память надо явно освобождать. Есть два встроенных аллокатора (heap и arena), но их можно менять прямо на лету:

// трассирующий аллокатор для отладки
track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator)

// context - неявная переменная,
// доступна в любой области видимости
context.allocator = mem.tracking_allocator(&track)

// можно поменять аллокатор
// хоть на уровне отдельного выражения
list := make([]int, 6, context.allocator)

Структуры, процедуры и итерирование (здесь и дальше я не пишу package и прочую обвязку):

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

Нет ни функций, ни методов — только процедуры.

Указатели объявляются символом каретки перед названием переменной, а разыменовываются кареткой после названия:

val := "Hellope!"

ptr: ^string
ptr = &val

fmt.println(ptr^)
// Hellope!

Немного непривычно, но выглядит логично.

Ошибки — просто значения:

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

Есть сахарок для нелюбимого многими if err != nil return:

balance := withdraw(42, 1000) or_return

Дженерики (параметрический полиморфизм):

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

Здесь pair_to_str принимает только значения типа Pair или производных от него.

Обзор языка

Как попробовать

Проще всего попробовать Odin в песочнице, которую я подготовил (именно в ней запускаются примеры из этой заметки).

Если предпочитаете локальную установку, на официальном сайте есть инструкция. Предоставляются бинарники для Windows, Linux и macOS — но, к сожалению, только amd64 (x86_64).

Если у вас arm64 Mac, можно использовать докер-образ (авторства Yeongju Kang с моими правками).

Специализация

Odin — язык общего назначения, но есть у него некоторая склонность к геймдеву и программированию визуальных эффектов. Наверно потому, что автор языка (Ginger Bill) — физик, который занимается как раз программированием визуальных эффектов.

Odin нативно предоставляет тип matrix и операции над матрицами, а также функции, связанные с SIMD/SIMT-программированием (о котором я ничего не знаю, так что лучше почитайте официальную доку).

Насколько я могу судить, многие программисты используют Odin именно для разработки игр.

Статус языка

Odin пока не добрался до версии 1.0. Нет даже роадмапа до этой версии. К тому же, он не так популярен, как Zig или Nim (скорее ближе к Hare).

Но компания, в которой работает автор языка, активно использует Odin в продакшене, так что проверку реальностью он уже прошел.

Надеюсь, у языка большое будущее!

Подписывайтесь на твитер, чтобы не пропустить новые заметки 🚀