260306_GC怖い病 という記事を昨日書いて、これから何言語を使っていこうという内容で終えていた。
主語としては「Luaの代わりに」という前提がつく。
表題にあるように、結論からいえばnimを選ぶことにした。
もちろんのこと自分が今後何か書くならとりあえず選ぶものは、という前置きがつくし、書くものや誰と書くかにもよってくるのだけれど、とりあえずこれで書こうというのをnimにしてみようかなと思うことにした。
理由はいくつかある。
メモリ消費量
一つはNeluaのメモリ消費量が大きかったこと。最初はLuaの代わりにNeluaで書こうと思った。が、デフォルトはGCオンなので、とりあえず何か書くとなれば当然GCをまずは使って書くことになる。
Neluaは万能で、Arena Allocatorもあるし、なんでもあるのでぶっちゃけなんでもできる一番万能なやつだと思うのだけれど、OdinやZigのように必ずしもカスタムアロケータをすべてのコンテキストで綺麗にスイッチできるわけではない。となるとやっぱりGCにはどこかで頼ることになる。
メモリ消費量が低くなっているベンチマークもいくつかあったのだけれど、自分が個人的に気になったベンチマークは↓。
https://qiita.com/Freezer/items/1badfbba34c13995eed4
elapsed timeと名前のついたグラフに実は縦軸にメモリ消費量が書かれていて、RubyやPHP並にメモリ消費量が大きかったという結果が出ている。
メモリ使用が激しすぎる言語はゲームに向かない というQiitaの記事があって、自分も概ね同感。もちろんのこと、前述の通りいくらでも最適化でき、正直LuaでもC-FFI使えば最適化できるし、JavaでもArena AllocatorやStack Allocatorは最近ではちゃんと使える。それでもそこまで最適化やるほどその言語で書きたいか、が一つポイントになる。
そうなると、とりあえず書いてうまくいく言語でないと、結局最適化問題が出てくる。GCに全く頼らないOdin等も捨てがたいのだけれど、ライブラリの充実度や、ORC/ARCなどのGCの選択肢の多さから、nimをチョイスしてみることにした。
C/C++のビルド知識が増えたこと
nimを何度もやろうと思ってやめたのは、出力されるC言語が読みづらいというのも大きいのだけれど、それよりも大きかったのは、ビルドを通すことができない、あるいは実行させることができない、ということだった。
nimはC/C++へのトランスパイラなので、当然ながら . h や .c/.cpp、.dll等への依存関係がほぼ必ず発生する。過去の自分は、LD_LIBRARY_PATH / DYLD_LIBRARY_PATH への理解が薄かったり、-rpath への理解が浅かったりした。
結局のところ、nimを書くならC/C++に詳しくなければならない。過去の自分はその知識が少なかった。
今はその辺の知識やノウハウがたまってきたことや、V言語・Odinを通してC/C++と連携する言語に慣れてきて流用できる資産も増えてきたので、今なら問題なく書けるように思う。
いざとなればV言語・Odin
まぁ、もしnimで困ったら最悪はV言語やOdinを使うし、結局のところC/C++を直接書くんじゃないかなと思う。その安心感が一番大きい。
Go言語ライクなV言語・Odinなどのファミリー(go-likesと呼んでもいいかもしれない)にしてもいいのだけれど、個人的にはちょっといろいろ辛い部分が多くて、Odinはクロージャがないとか、関数型ライクな書き方を許容しないとか、メソッドっぽいものがほぼ作れないとか、それゆえDSLっぽく書けないとか、不満は尽きない。
nimはそんななかでは自分は一番好きな言語の一つで、nimで困っていたことの多くはC/C++関連ばかりだった。結局のところ、nimが好きになれるかはC/C++が好きになれるかに依存している部分が多くあるように思う。
自分はC++は好きではないのだけれど、Cは嫌いではないし、C++のメタプログラミングが嫌いというだけで、外部ライブラリとして呼び出すだけを考えればそのあたりの知識は正直要らない。知識もないわけではないし。
ということでとりあえずはnimでしばらくいろいろ書いてみようかなと思う。
ところでgo-likesを紹介してなぜGoを使わないかといえば、ebitengineが圧縮テクスチャ等のストリーミングに対応していなかったり、kaijuはよさげかもと思いつつも使い方がよくわからなかったりと、ちょっと時期尚早かな感があるので、puregoを使ったライブラリ等がもう少し成熟してきたらまたウォッチするかもしれない。