前からずっと気になっていた、Odin言語を重い腰を上げて使い始めた。
https://github.com/funatsufumiya/odin-studies
## 今更使い始めた理由今更使い始めた理由はいくつかあって、
- V言語やebitengineによってGoライクな言語に慣れた
- GCなし言語を使いたいニーズがあるが、Zigはすべてが見える化されているものの制御が細かすぎて人に勧めにくく、Rustは関数型由来のゼロコスト抽象化が美しいものの、難しすぎて人に勧めにくい。
- Odin言語がなぜ選ばれるかがわかった
特に最後の一つについて、理由は後述するものの、実は自分の中で引っかかっていた点があった。
- Zigと比べてOdinは完成度 1 や人気が微妙…?あとコンパイラすら内包しているZigはいろいろ魅力的。
- 手動メモリ管理が不安
- クロスプラットフォームなライブラリが少ない印象
Odinの「楽しく書けること」と「シンプルさ」
Odinがなぜ選ばれるかは、特にZigやRustと比較した場合、あえて中庸(中道)な言語として作られているという点にあることに気づいた。
正直、GCの有無以外はV言語に通じる部分がすごく多い(Goライクな点も含めて)のだけれど、Zigがすべてを見える化してすべてを制御しようとしているのに対して、Odinは「楽しく書けること」と「シンプルさ」をすごく大切にしていて、アロケータについてはContextという概念を使って見えないようにしている。
これによって何が得られるかといえば、まるでスクリプト言語のような書き心地でありながら、C言語のように手動メモリ制御ができるという、ありそうでなかった両立をしているのだということに気づいた。
実際、スライスの概念があることなども含めて、書き心地はまるでPythonとかのようなスクリプト言語に近いとすごく書いてて感じる。つまり楽しい。
Battery Included で、SDL3やwgpu、wasmへの期待
ぶっちゃけ、GCありで問題がない部分については自分はV言語をこれからも使い続けていくだろうと思うのだけれど、Odinは vendor ライブラリと core ライブラリがV言語並に充実していて、V言語が描画周りを最近は sokol に全振りしているのに対してOdinはDX/Metal/Vulkanへのアクセスを標準で提供しつつ、かつ raylib を標準で利用できたり、wgpu すら標準で利用でき、最近では Orcaをサポートすることでwasmで動くしクロスプラットフォームで動くという未来も見えてきている。
自分の中で、Odinで書くとDX/Metal/Vulkan/GLにはアクセスしやすい一方、sokol等のラッパーがちょっと辛いかもというか、ラッパーはあるけれど低レイヤーすぎて、bevyとかGodotまでいかなくてもエンジンがない印象だった。が、jamgine のようなエンジンライクなものも出てきているし、最近は SDL3 が登場してOdinも標準サポートしているし、Raylib自体もすごい速さで進化している。
Odinを使い始めようと思ったのは、この辺への理解とか安心感がようやく得られたことが大きい。
あと何より、V言語で何ヶ月か遊んで、C言語へのラッパーを書くことがそんなに難しいことではないというのが実際に体感できたことも大きい。ただOdinはFFIベースなので、TinyCCを内包しているV言語や、C/C++/JS自体を吐くNim、コンパイラを内包してC/C++を直接呼べるZigに比べれば、ラッパーは多少苦労するだろうなという予感はする。
でも、bindgen的なものはあるし、何よりOdinはCとすごくよく似ているし、V言語やbunのようにGCとの兼ね合いを心配することは基本的にないので、不安はないだろうと思う。
手動メモリ管理への恐怖
ということで最後に残っていたのがこれ。こればかりは仕方ないだろうと思う。
が、これもV言語の影響が大きいのだけれど、Go言語由来の defer と、Zig同様のアリーナアロケータ等のメモリ集中管理システム、そしてZig等と同じくメモリリークを的確にトラッキングできる TrackingAllocator の存在。
こう書くと、Odin = (Go + Zig) / 2 と思ってもぶっちゃけいいんじゃないかと思うくらいには、中庸 (中道) なというべきか、良いところどり言語なのだといえると思う。
実際、Zig等と似たカスタムアロケータによるメモリアロケーションのトラッキングは非常に強力で、ぶっちゃけ思っていた以上だった。どこでメモリがリークしたか、当該箇所が行単位ですぐわかるし、2回解放してしまっている箇所もすぐわかる。これはZig同様にすごく安心できるポイントだった。
あと後述するけれど、ゲーム開発などで所有権が不明確なケースは(体感として)ほぼない。少人数開発であればなおのこと。
GC(やARC/ORC)がやっていること
あとは、GCというのが何をしているかを突き詰めることにあるように思う。C++のスマートポインタも含めてNimのORC/ARCしかり、この辺の自動メモリ管理をひっくるめてGCだと仮にしておく。
GCがやっていることは結局、ヒープに動的に割り当てられて使い回されているメモリ領域について、捨てられた、つまりもう使われないことを判定し、削除すること。
なぜ使い回されるかといえば、所有権の不明確さ等にある。バトンを渡していくみたいなイメージが一番わかりやすいだろうし、RustのArc等、並列処理になるとさらに事は複雑になる。
ただ実際のところ、所有権が不明確なケースってどれだけあるかといえば、ごく少ない。だからこそRustの所有権システムによって大半が綺麗に整理されるし、所有権が使えない unsafe な領域になれば、当然ながらRustの所有権システムは(unsafeな箇所に限って)意味をなさなくなる。
どういうときに所有権が不明確になるかといえば、ぶっちゃけ大人数で開発しているときと、どんな人がコードを書くかわからないケース(ブラウザのHTML/JSなど)だろうと思う。そういうときは正直制御できる範囲が限られてくるはずで、よく設計されていない限りは限界があるので思い切ってGCやARC/ORCを導入したほうがいい。
Godot等もRC(参照カウント)によって、高速動作しながらもGCを両立することに成功していて、この辺はNimも同様。一方でV言語や.NET (Unity)、Racket のように、GCを積んでいても(メモリ使用量やCPU負荷などのオーバヘッドはありつつも)実際には問題なくリアルタイム領域で動作するものもある。
…結論として、自分はどちらでも良いと思う。アプリケーションレイヤーとしてはどちらでも良い。ただ、特にC-ABI経由で呼ぶライブラリを作るときは、GCがないに越したことはない。そうでないと呼び出し側が困ることになる。(呼び出し元にGCがあると、アプリケーションサイドのGCとバッティングしてしまうことになるので、結局どこかに unsafe なコードを生み出すことになる。)
話が少し飛躍した感はあるけれど、結局Odinを使おうと思った理由は、自分一人で書く、数人で書くくらいのコードなら、所有権の管理くらいは所有権システムがなくたってできるという事実。
それによってRustのような複雑なエラーメッセージの理解や、Rust/C++のようなゼロコスト抽象化のための高度なテンプレートや関数型やマクロを捨てることができるのであれば、脳負荷を下げるために捨て去ったほうがいい、シンプルにいこう。やりたいことにまず集中して、完成してきて何か困ったらその時になってから難しいことは考えよう。というのが今の自分のスタンス。
仮にそれで問題が出ても、カスタムアロケータによってメモリをトラッキングして原因追求できるし、何よりシンプルな言語は読みやすい。マクロもなく複雑な見えない処理が少なければ、すぐ読める。
そして、楽しく書けるなら、人はすぐ集まる。
というのが今現在の自分のスタンス。
V言語やRustやNimは?
ちなみに改めて他の言語について、使わなくなるかといえばそんなことはない。関数型チックに書きたいときだってあるし、先日musl関係で思い知ったように、時々は特定の言語で書かないと回避できない(後日回避できたけど)問題もあるし、何よりGodotのGDExtensionのように、自由に好きな言語が選べるというのが一番いいと思う。最終的にはC-ABIやwasmで繋がっているのだから。
自分は大学時代からずっと今まで、結局のところ、『7つの言語 7つの世界』の語る世界が楽しいとずっと感じているのだと思う。気分で言語やデバイスやプラットフォームやライブラリを変えながら、根底ではC-ABIや機械語や圏論のような深いもので繋がっている世界。
だから結局なんだかんだいってGodotみたいなものに落ち着くような気がしているのだけれど、その時々で好きなものを選べるというのが、一番の贅沢なんじゃないかと。(で、結局Odinの中身には大して触れることなく記事を締める…。)
次の目標: Raylibで遊ぶ、Sokolで遊ぶ
記事を締めると書いたけれど、次の目標としては、まずはRaylib等で散々遊び尽くしたい。で、V言語では普通にできる、普通のGUIアプリケーションの作り方くらいは知りたい。(できなければ microui 等で誤魔化す。)
【追記】普通のGUIアプリケーションは、odin-webui を使うのが安定している感じだった。oruiも即時GUIとしてはすごくよかった。
で、Delve Frameworkや、せめて ggのような、Sokolが気軽に書けるラッパー(つまりはラッパーのラッパーか?)が欲しいなと思うので、それは長期目標としてどこかで達成したいし、その過程でv_gvvideoなどを少しずつ (Pure) Odinに移植するか、C言語経由のラッパーを書ければと思う。
Footnotes
-
完成度については、正直アーリーステージであることは否めないと思うけれど、EmberGenのようにプロダクトが既にあることや、パッケージ管理についてはフォルダベースでいく、クロージャーは作らないなど割り切っていることから、他の言語よりも完成に近づく速度は速いとは思う。ただ、差分ビルドがまだなかったり、破壊的変更が未だにあったりなど、2025年現在ではやはりアーリーステージであることは意識していなければならないと思う。 ↩