clojureのシリアライズ系ライブラリを試した

要は、ゲームの進行状況を保存する為に、各変数の内容を文字列もしくはバイト列に読み書きしたい為。
今まではedn( http://clojure.github.io/clojure/clojure.edn-api.html )をそのまま使っていたが、これはjava arrayやatom, ref等をサポートしておらず、副作用バリバリに変数内容を変更する事が多いゲーム向きではなかったので。


チェック内容は以下の通り。

  • java arrayが読み書きできるか。特にobject-arrayの中身がS式だった場合でも正しく扱えているか
  • atom, refが読み書きできるか(ただし今回の調査では面倒なのでatomしか調べてない)
  • オブジェクトのトポロジカル構造が維持されるか
    • これは要するに、以下のようなオブジェクトをwrite/readした後に、carとcadrが同じオブジェクトとして再現されるか、という事。
(let [a (int-array [1 2])] (list a a))


以下を試した。

  • edn (org.clojure/clojure "1.5.1") http://clojure.github.io/clojure/clojure.edn-api.html
    • java array : △ (要カスタム指定)
    • atom, ref : △ (要カスタム指定)
    • topological : × (Schemeでの #0# 的な奴がないので絶望的)
    • 備考 : write時に自分で「#」でタグ付けし、readにオプションとして :readers を渡せば、一応java arrayやatom類を読み書きする事は可能。しかしwriterを書くのが面倒(これさえどうにかできれば、pr-strで一発dumpできるし標準付属なのでお手軽なのだが…)
  • carbonite (com.twitter/carbonite "1.3.2") https://github.com/sritchie/carbonite
    • java array : ×
    • atom, ref : ×
    • topological : ?
    • 備考 : これもカスタマイズ指定が可能なようだが面倒なので試してない。最近はあまりメンテされてない様子
  • Deep-Freeze (deep-freeze "1.2.2-SNAPSHOT") https://github.com/halgari/deep-freeze
    • java array : ×
    • atom, ref : ○
    • topological : ×
    • 備考 : java array以外に、symbolのシリアライズができないという問題もあり。今回試した中で、標準でatomを扱えたのはこれだけだった。最近はあまりメンテされていない様子
  • Cheshire (cheshire "5.3.1") https://github.com/dakrone/cheshire
    • java array : ×
    • atom, ref : ×
    • topological : ?
    • 備考 : dumpしたデータはjsonになる。これもカスタマイズ指定での変換は可能だが試してない


感想:

  • どのシリアライザもトポロジカル構造を再現してくれない!Common LispSchemeなら大体は標準完備なのに…
    • これはおそらく、clojureが「immutableなデータ構造」を前面に出している事が逆に悪い影響になっている気がする。トポロジカル構造を再現しないとまずいのは大半が破壊的更新時だと思うので。
    • atomとrefを標準でサポートしていないシリアライザがほとんどなのも、これらをサポートすると「トポロジカル構造の維持」が必須になってくるからでは、と思う。でもその割にはobject-arrayは平然とサポートしている。


セーブロードで利用したいという要望に対する結論:

  • どのシリアライザもトポロジカル構造を再現してくれない為、参照構造をそのままセーブデータとして書き込む事ができない。よって、マップ&キーワードもしくは配列&インデクス値を使い、間接的に参照を保持せざるをえない。超めんどい。
  • atom類については、Deep-Freezeは標準対応しているが、Deep-Freezeは他に問題が多いので却下したい。そして他には簡単に扱えるものはないので、atom類は使用しないで、参照を保持したい時はobject-arrayを使うようにすべき、という結論に。
    • とは言え、上記の通り、そもそも「参照を直に保存できない」という結論が出ている為、基本的にはインデクス値指定を多用すると思われるので、こっちについてはそれほど大きな影響はないと思う。
    • なお、変数そのものを更新したい場合は、alter-var-rootで直に更新する。
  • とりあえず「そのままjava arrayが扱える」グループの中でも、一番扱いやすかったnippyを採用しようと思う。


参考にしたリンク/関連リンク: