前置き: jankがいよいよ使えるようになってきたかもしれない
先に共有したjank-glfw-test、MSYS2ではないWindowsでも普通に動いた。
https://github.com/funatsufumiya/jank-glfw-test/
どうやって動かすかというと、jank-winに書いてあるように C:\msys64\clang64\bin\jank.exe にパスを通せばいいのだけれど、それだと結果的にMSYS2 Clang64のすべてにパスが通ってゴチャゴチャしてしまうので、以下のようなbatファイルを作って jank.bat として保存し、パスの通ったところに置けばいい。
@ECHO OFF
C:\msys64\clang64\bin\jank.exe %*あとは、lein (leiningen) を通常通りインストールすれば、問題なく使える。leinはjankとは独立しているので、別にMSYS2のを使う必要はない。
ちなみにMSYS2から離れるデメリットとしては、動的ライブラリやヘッダーパスなどの依存関係の解決が少し手間になることだけれど、nimもそうしているように、上記Gitリポジトリのようにフォルダ内で完結していれば特に問題はない。
もうここまでくれば、jankは至極当たり前のようにWin/Mac/Linuxで利用できて、nimなどの言語に並んだように思う。まだClojureとしての機能面がもう少しな部分はあるらしいけれど、体感的には特段支障はない。
これで、前から夢見ていた、Clojureを実用するという夢が現実のものになりそうだ。Clojureがゲーム開発などでメインステージに躍り出る未来もそう遠くはないと思う。
・・・となると、nimとの違いはなんだろうか。
nimとjankの違い ~ 静的か動的か
nimとjankの一番の違いは、あくまで現時点ではかもしれないが、jankではC++の静的ライブラリが使えないことだろうか。jankは動的言語であり、静的言語ではないので、当然の制約とは思う。
両者の共通点は、C/C++とダイレクトにアクセスすることができ、型を相互に変換し合うことができること。そして、ポインタ操作などが可能で、nimでは {.emit.} プラグマ、jankでは cpp/raw によって C++ コードを直接書くことができて、それらが当たり前かのように呼び出しができる。
jankも元々はnimのようにC++にトランスパイルすることでそれを実現していた。しかし、C++のコンパイルが遅いとのことでLLVMへの移植が踏み切れられた。
余談として、nimにも実は nlvm というLLVMバックエンドが存在する。ただし、jankのように埋め込まれた生のC++コードをその場で動的にコンパイルしてリンクするような芸当はまだできないようで、以下に記載があるように {.compile.} で {.emit.} を代替するように書かれている。(あれーコンパイルできてるじゃんと自分は素直に思ったのだけれど、直接C++コードをemitできるようになるのはまだ先っぽい。)
https://github.com/arnetheduck/nlvm?tab=readme-ov-file#emit
そういう意味では、jankはnimよりも少し先にあるという見方もできるだろうし、LLVMという巨大な依存関係ツリーを持ってしまって大変だという見方もできる。
先に書いたように、jankは動的言語であることもあり、C++の静的ライブラリが使えない。これはPythonとかRubyとかみたいな言語からすれば至極当たり前のことで、普通といえば普通のこと。
C++の静的ライブラリを使いたいなら、jankを再コンパイルして最後に埋め込んでリンクする形になるだろうけれど、それはなかなかヘビーなことだろうと思う。LLVMも内包しているわけだし。
C++との密な連携を謳うnimとjankの一番の違いがここに出ていて、C++のライブラリは結構静的ライブラリ (Static Library) で配布されていることも多いので、ここが問題になりそうに個人的には思う。
実際、openFrameworksやTrussCなど、特にopenFrameworksなんかは多くの静的ライブラリに依存している。ここをすべて動的ライブラリにするという作業は、個人的には大変な作業なんじゃないかなと思っているのだけれど、もしかすれば簡単にできる手段があるのかもしれない。
ぶっちゃけこれ(C++コードとのリンク)さえ済めばあとは好みの問題になってきて、静的言語が好きか動的言語が好きかという話に帰着するんじゃないかと思うのだけれど、Clojureの場合はJavaとの連携性のために型を記載することができた。jankの場合は、一応cppの型を場合によって明記することもできはするけれど、cpp以外の型の明記をClojureのように ^bool とか書く方法は自分は今のところ知らない。今後拡充されていくのかもしれないし、されないのかもしれない。
ただClojureは型をおまけ程度に記載することのできるだけの動的言語なので、他の動的言語同様、テストケースで網羅しないとエラーを含むコードも当然ながら含めて実行できる。
これは大規模プロジェクトでは結構怖いことだろうなとは思うけれど、Clojure自身もこれに対する多くのノウハウを持っているし、JavaScriptやLua、Pythonがそうであるように、型ヒントについての支援はユーザが増えれば増えてくるかもしれない。
自分は学生時代にRubyが大好きで、大学生~大学院生のときにRubyで作ったDSLをいくつも作って遊んでいたし、Clojureも本当に楽しかったので、jankは相性がいいとは思う。
けど実際社会人になって仕事ではJavaやC++が中心になって、静的言語に慣れているし、型システムの恩恵を多分に受けて生きてきているので、そういう意味ではnimが相性は今は良い。それに、DSLで遊んでいた経験はnimでもそのまま生きている。
なので、今はnimで小さなプロジェクトからC++の代わりとして使っていき、水面下でjankでのノウハウをためつつ、同時にjank言語の成長を見送りながら、そしてClojureの知識を改めてつけながら、少しずつjankおよび動的言語に向き合う素養をつけていけたらなと思う。
Programming Clojure 4th Edition by Alex Miller
Clojureの知識という文脈で思い出したのだけれど、そういえば、Clojureの最新の本が4月に出るらしくて、ベータ版が出ている。自分はベータ版買った。
https://pragprog.com/titles/shcloj4/programming-clojure-fourth-edition/
同じタイトルのClojure本は13年ほど前に出ているけれど(川合さんが訳者のやつ)、それとは作者が異なる。自分はこの新しい本もぜひ日本語で読みたくて、作者にClojurians Slackでコンタクトをとって日本語化に協力したい旨を名乗り出ているけれど、今のところまだ返事はないので様子をみようかなと思う。
nimとjankという両刀
元々自分はいろんな言語を使ってきたのだけれど、最近はC/C++に落ち着きつつあって、他の言語や他の開発者がそうであるように、Pythonなどのグルー言語でC/C++の資産を呼び出すことが多い。
グルー言語は動作が遅いのが常識だったのが、nimやjank、neluaなどによって常識は一変しているし、なにより、CではなくC++とシームレスに会話ができるグルー言語はなかなか存在しなくて、特にゲーム開発などではその恩恵は計り知れないと思う。
C++と別にRustが台頭してきているけれど、RustはRustの世界で完結しつつあって、大きな流れとしてはWASMの方にみんな目が向いているっぽい。もちろんRustでネイティブを書いているものもZedエディタのようにあるけれど、BevyもそうであるようにWebGPUやWASM関連リソースとの関連が深いのは事実。
自分は結構センサーとか含めてWebではない本当の意味でネイティブなものが好きだし、Rust自体ちょっと制約きつくて自由じゃなくて辛いなというのもありつつ、Rustがもう少しライブラリ文化を持ってくれて他の言語とも疎通ができるようになれば使うのだけれど、C-ABIのようにはRustはなりそうになくて、RustはRustの道をいきそうなので、なかなか自分はついていけなさそうな気はしている。(ただ、fdとかrgとかZedとか便利なツールは多くあるので、利用はしていくとは思う。)
そういう意味で、C/C++がベースにある時代はまだまだ長く続くだろうし、OdinやZigなどもC-ABIを基調に書かれているため、C-ABIに親和性の高い言語はまだまだ長く残るだろうと思う。
C++がいつまで使われるかはわからないけれど、現状C++資産やCMake資産が多くある中では、nimとjankは末永く力になってくれるんじゃないかな。Godotでもgdextensionが似たような形をとっているし、C/C++がバックエンドになって別の書きやすい言語がフロントになるという構図は、今後もかなり長く続くんじゃないかなと自分は思う。
(最後に注意として、nimとjankでいうと、jankは実際のところは例えばどれくらいGCの精度やチューニングができるか、本当にメモリ関連のトラブルはないかなど、まだ正直よくわからない部分も多い。nimは2.2.8とかなり安定した言語なので、実用上はnimを使うのが安全牌ではあると思う。)