C++を使った数値計算ライブラリの整備で辛かったこと
まえがき
この記事はC++を批判する意図はなく, 過去10年以上の数値計算ライブラリの開発経験を共有する目的で書かれている.
まとめ
特に, 標準的なパッケージマネージャー, コンパイラー, ビルドシステムの不在が辛い. 以下に項目ごとに具体的な感想を書いていこう.
標準的なパッケージマネージャーの不在
Julia, Rustなどに存在する統一されたパッケージマネージャーがC++には存在しない. これにより, 以下の困難が生じる.
- 自分が開発しているライブラリを機能ごとに分割しづらい. 例えば, いくつかのライブラリで共通の機能 (例えば, full-pivoting LU) を共通に使っている場合, その機能を単独のライブラリとして切り出したいことがある. これにより巨大なライブラリを機能が明確なライブラリ群に分割して管理しやすくなる上, コードの再利用が容易になる. しかし, 標準的なパッケージマネージャーの支援なしには分割は難しい. 結局, 巨大なモノリシックなライブラリやソフトウェアを作ることになる (油断すると, すぐにスパゲッティコード化する).
- 他者が書いたライブラリを再利用しづらい. 配布を容易にするために, 自分で再実装することになる.
- 作成したライブラリ・ソフトウェアを配布する際に, 依存するライブラリのインストール法など多岐に渡る点の配慮が必要になる.
ビルドシステム
上述の話にも関連しているが, ビルド時の依存性や手順などを指定するビルドシステムが多数存在する. 最近ポピュラーなのはCMakeだろうと思うが, 依存ライブラリの検出を安定的に行うことは難しく, 文法も一般的なプログラミング言語とはかなり異なる (すべての変数が文字列). 私は, LLMの助けなしには書くことが困難だった...
C++には規格がある. 新しいものほど標準ライブラリが充実したり, テンプレートを書きやすくなる. しかし, 最新の規格を使ってしまうと, コンパイラにバグがある可能性が高く, コンパイラごとに対応が必要になる. また, 配布する際にも, あらゆるコンパイラでのチェックが必要になる.
独立した実装があることはコミュニティにとって良いことではあるが, 便利な機能を使って楽をしようとすると, 逆に無用な労力を使うことになる.
さらに, 異なるコンパイラやバージョン間でABI互換性がない. つまり, 異なるABIを持つコンパイラで作成した複数の共有ライブラリを混ぜて使うことができない. これは, 最終的なソフトウェアに必要なすべての共有ライブラリのビルドの際に, ABI互換性が保証されたコンパイラを共通して使う必要があるということを意味する. これをユーザーに要求するのは極めて難しい.
もちろん, 内部実装はC++でも, C-API
のみを利用して他のライブラリと連携する方法もある (例えば, 我々が作成した libsparseir でその設計を採用). しかし, C-API
の整備はかなり技術的に難易度が高く, 手間もかかり, メモリ安全性も低い.
メモリ安全性
C++で書きたいものは, およそ基盤・低レベルのライブラリか, 大規模並列化向けの高性能アプリケーションソフトウェアが多いと思う. 静的な型付け言語であるC++はそれに向いているように思うが, その割に危険な挙動を簡単にできてしまう.
例として,
- 一時オブジェクトへの参照を関数から
return
してしまう - 同じオブジェクトへの書き込み権限を持ったオブジェクトが複数存在する
などがある. 特に後者はJuliaやPythonでも同じであるが, こちらは生産性を優先した言語で, 設計上許容されていると思う. しかし, 安定してほしい基盤・低レベルライブラリを書くときに, このようなヒューマンエラーを機械的にチェックしてくれないのは辛い.
多次元配列と線形演算の標準的サポート
標準的なライブラリはEigen3だと思う. JAXのバックエンド等にも使われている. メインブランチへのコミットは続けられているが, 最後のオフィシャルなリリースは2021年に遡る. また, 多次元配列のサポートは, まだ非公式機能扱いである. とりあえずバグには遭遇しなかったが, このままでいいのか.
ドキュメント作成の標準的な仕組みの欠如
C++には, JuliaのDocumenter.jlやRustのrustdocのような, 標準的なドキュメント作成ツールが存在しない. 結果として,
- APIリファレンスやユーザーガイドの自動生成が困難
- プロジェクト間でドキュメントのスタイルやフォーマットがバラバラ
- ドキュメント作成が後回しにされがち
という状況になりやすい. 実際にはDoxygenやSphinxなどを組み合わせて使うことが多いが, セットアップが複雑で初学者にはハードルが高い. また, コメント形式がプロジェクトごとに異なっていたり, マークアップの流儀も統一されていない.
ライブラリを他人に使ってもらおうとしたとき, ドキュメントが整っていないのは致命的だが, そのためのサポートが言語側から一貫して提供されていないのは辛い.
Discussion