Cが最良だ(2025)
(sqlite.org)- SQLiteは2000年からC言語で実装された軽量データベースエンジンであり、他の言語に書き換える計画はない
- Cは性能、互換性、依存関係の少なさ、安定性の面でSQLiteに最も適した言語と評価されている
- オブジェクト指向言語(C++、Javaなど)は言語間呼び出しの制約が大きく、手続き的アプローチのほうがむしろ単純で高速な場合がある
- RustやGoのような**「安全な言語」**はまだ十分に成熟しておらず、SQLiteの品質戦略(例: 100%分岐テスト、OOM復旧)に適合しない
- 将来的なRustへの移植の可能性はあるが、成熟度・互換性・性能・ツール支援など複数の条件が満たされる必要がある
1. Cが最善である理由
- SQLiteは2000年5月29日に最初から標準的なC言語で実装され、現在に至るまで他言語への移行計画はない
- CがSQLite実装に適している理由として、性能、互換性、低依存性、安定性が挙げられている
1.1 性能
- SQLiteは集中的に利用される低水準ライブラリであり、高速性が必須
- 例として「Internal Versus External BLOBs」、「35% Faster Than The Filesystem」の文書で性能が示されている
- Cは**「移植可能なアセンブリ言語」**と呼ばれるほどハードウェアに近い制御を提供しつつ、プラットフォーム間の移植性も維持する
- 他の言語が「Cと同じくらい速い」と主張することはあっても、Cより速いと主張する言語はない
1.2 互換性
- ほぼすべてのシステムがCで書かれたライブラリを呼び出す機能を提供している
- たとえばAndroidでは、JavaアプリケーションからSQLiteをアダプタ経由で呼び出せる
- もしSQLiteがJavaで書かれていたなら、Objective-CやSwiftベースのiPhoneアプリでは利用できなかっただろう
1.3 低依存性
- Cで書かれたライブラリはランタイム依存関係が非常に少ない
- 最小構成ではSQLiteは標準Cライブラリの次の関数だけを必要とする
- memcmp(), memcpy(), memmove(), memset(), strcmp(), strlen(), strncmp()
- 完全ビルドでもmalloc()、free()、ファイル入出力程度しか使わない
- 一方、現代的な言語は数MB規模のランタイムと数千のインターフェースを要求する
1.4 安定性
- Cは古く、変化の少ない言語であり、明確で予測可能な動作を提供する
- SQLiteのような小さく、高速で、信頼性の高いデータベースエンジンを開発するうえで、言語仕様が頻繁に変わらないことは重要である
2. オブジェクト指向言語で書かれていない理由
-
複雑なシステムはオブジェクト指向言語でなければ実装できないと考える開発者もいるが、SQLiteはそうではない
-
C++やJavaで書かれたライブラリは、同じ言語で書かれたアプリケーションでしか使えない
- 一方でCライブラリはほぼすべての言語から呼び出せる
-
オブジェクト指向は設計パターンであって言語そのものではなく、Cでもオブジェクト指向的な構造を実装できる
-
オブジェクト指向が常に最善とは限らず、手続き型コードのほうがより単純で、保守性や性能の面で有利な場合もある
-
SQLite開発初期(2000年代初頭)にはJavaは未成熟で、C++はコンパイラ間の互換性問題が深刻だった
- 当時はCが明らかにより良い選択であり、現在でも書き換えによる利点はほとんどない
3. 「安全な言語」で書かれていない理由
- 近年はRustやGoのような**「安全な言語」**が注目されているが、SQLiteは依然としてCで維持されている
- SQLiteの最初の10年間には安全な言語が存在しなかった
- GoやRustで書き直すことはできるが、新たなバグ発生と速度低下のリスクがある
- 安全な言語は**配列境界チェックなどの追加の分岐(branch)**を挿入する
- 正しいコードではその分岐は実行されないため、100%分岐テストは不可能
- ほとんどの安全な言語はメモリ不足(OOM)時にプログラムを停止させる
- SQLiteはOOMでも正常に復旧するよう設計されており、この挙動と相容れない
- 既存の安全な言語はどれも新しく、急速に変化している
- SQLiteは古く安定した言語を好む
4. Rustへの移植可能性
- SQLiteがRustに書き換えられる可能性はあるが、Goへの移植はほぼ不可能
- 理由: Goはassert()を好まない
- Rustへ移植するための前提条件
- Rustがさらに成熟し、変化の速度が落ちて**「古く安定した言語」**になること
- Rustがあらゆる言語から呼び出せる汎用ライブラリを生成できること
- OSのない組み込みデバイスでも動作するオブジェクトコードを生成できること
- 100%分岐カバレッジテストを支援するツール体系を備えること
- OOM復旧メカニズムを提供すること
- C水準の性能劣化のない実装を証明できること
- Rustがこれらの条件を満たしていると考える開発者は、SQLiteチームに直接連絡して議論できる
5. 結論
- SQLiteは小さく、高速で、信頼性の高いデータベースエンジンであり、C言語の特性がその目標に合致している
- オブジェクト指向や安全な言語への移行は、互換性、性能、品質管理の面で実益がない
- Cの単純さと安定性がSQLiteの長期的な保守性と信頼性を支えている
8件のコメント
どうせPRも受け付けないプロジェクトなんだし……自分たちが使いたいものを使ってるってことですね
コンパクトさが求められる状況なら、C、C++、Rustを代替できる言語はありません。構造体や
mapでビット単位のオーバーフローやハッキングを懸念しながら開発することに共感する開発者が、あまり多くないだけでしょうタイトルが刺激的すぎますね。元の記事を見れば、なぜ C が SQLite の開発に最も適しているのかについて書かれた文章だと分かります。皆さん、どうか怒りを鎮めてください
いや、しかも文章そのものも書かれたのは7年前なんですね? その後ろに内容を付け足しながら、2025年に一部更新された感じみたいですが……🤦
さまざまな開発状況に適した言語を使う、そういう判断ができることが重要なのであって、特定の言語が常に優れているかのように、ああいうタイトルを付けるのは、思考のレベルが中卒だ……
Cの最大の長所は、「コンピュータはビット列である」という本質にそのまま触れている点にあると思います。Cの単純な哲学と過激な
reinterpret castingによって、ユーザーはほとんどの場合、それがどのような機械語に翻訳されるかを把握できるという魅力があります。あらゆる言語から呼び出せるのはCだからではなく、呼び出し可能なのはABIであり、Cでは単に入出力がどのようなビット列なのかを予測しやすい(あるいはそうであるべき)からなのでしょう。常に実装可能性について議論するときにも、これがチューリングマシン上で不可能なのか、それとも今使っている言語やフレームワークで不可能なのかを区別することが重要だと思います。Hacker Newsの意見
すべてのプロジェクトやプログラマーがRustやZigを使わない理由を、わざわざ正当化する必要はないと思う
Hacker Newsや他のプラットフォームでは、これらの言語が過度に押し出される傾向がある
Cで十分によい結果を出していて、ユーザーも満足しているなら、外部がとやかく言う理由はない
技術の進歩に関心のある人たちが新しい言語の可能性を探るのは自然な流れだ
ただし外部が意見を述べる自由はあっても、プロジェクトにそれを聞く義務はない
Rustはバグの露出を減らすが、同種のバグは依然として存在する
C開発者は競合状態により敏感に反応する傾向があり、Rustでは「安全」という注釈を過信するリスクがある
またRustでは修正が単純ではなく、リファクタリングの負担が大きくなることがある
結局Rustは興味深い言語ではあるが万能ではなく、強制すべきではないと思う
RustやZigのような言語は、従来のオブジェクト指向パターンから離れようという意図を持っている
OOPはかつて「悟り」を与える概念的枠組みとして魅力的だったが、実際には複雑性を増やし、モジュール性を損なうことが多い
手回しドリルではなく電動ドリルを使うのが当然であるように、よりよい道具があればそれを使うのは自然だ
ただし、安全なCコードを書けるツールや教育も十分に発展する必要がある
私はかなり真剣なRustaceanだが、すべてのプロジェクトをRustで書き直すのは合理的ではないと思う
すでによく検証されたCプロジェクトをRustに移すと、短期的にはむしろバグが増える可能性が高い
ただし一部ではRustへの再実装に挑戦しており、たとえば Limbo: SQLiteをRustで完全に書き直したプロジェクト がある
SQLiteの主な利点の1つは複数プロセスから同時にアクセスできる点で、これが欠けると活用範囲が狭まる
自分で新バージョンを作って、成功するかどうかを試せばよい
RediSearchをRustへ移行した経験がある
これは最近CVE脆弱性が多かったためだった
SQLiteにこうした問題がないなら、Rustへ移す理由は弱い
Rustの強みと限界を理解するには、数十年の時間が必要になりそうだ
特にGUIアプリケーションでのRustの有効性はまだ不明確だ
Rustが同レベルの信頼を得るには、2040年ごろまでかかるかもしれない
Linusが言及したように、RustにはOOM(Out of Memory)回復メカニズムが必要だ
関連内容は LKMLの議論リンク で見られる
組み込みやカーネルコードでは割り当て機能を完全に無効にもできる
つまりRustはすでにメモリ制御権を完全に提供している
「Cより速い汎用言語はない」という主張は、開発者の時間を無視した断片的な比較だ
Cで5時間かけて4秒のプログラムを作るより、他の言語で5分で5秒のものを作るほうが現実的なこともある
ユーザー数が多いほど、わずかな速度差でも累積価値は大きい
Rustが「退屈で安定した」言語になるにはまだ遠い
Cは保守的な委員会が管理し、互換性を徹底して守る一方で、Rustは問題解決のために互換性より革新を優先する
古いバージョンのコードも新しいコンパイラで引き続きビルドできる
これはC++のように過去の機能を抱え続けるアプローチより良いと思う
一方でC++やCommon Lispのような委員会設計言語は複雑性が増した
Rustも規模が大きいため、組み込みや中核システムでは慎重に使うべきだ
「うまく動いているものをわざわざ壊すな」という態度に共感する
言語発展の歴史は、問題を解決しようとして新たな複雑性を生む過程の繰り返しのようだ
Cは「Worse is Better」哲学の代表例で、単純さのおかげで数十年にわたり成功してきた
Rustは逆に「Right Thing™」を志向する
今日では多くの環境で自前実装の負担が減っているため、今ではより良い選択になり得る
しかし、すでに成功しているプロジェクトをわざわざ移す必要はない
新規プロジェクトならRustのほうが良い選択である可能性が高い
Cの単純さと安定性は過小評価されている利点だ
言語自体を変え続けるより、標準ライブラリやエコシステムを磨くほうが良いと思う
単純さだけでなく、決定的な動作保証も重要だ
たとえば designated initializer、compound literal、alignas、memset_explicit のような機能が気に入っている
個人的にはCが今でも最高だと思う
Rustには良いアイデアが多いが、欠点もはっきりした言語だ
まだRustの問題点を冷静に議論しにくい雰囲気がある
たとえば 学習曲線 や パッケージングの複雑さ のような部分があるかもしれない
「すべてのシステムがCライブラリを呼び出せる」という言い方は、もはや事実ではない
RustやZigもこの要件を満たしている
ただしRustの標準ライブラリは、OOM時に回復せずパニックすることが多く、文書化も不足している
extern "C"やexportを使わないとC ABI互換にならないそうでないとABIが定義されず、むしろC++より不安定になり得る
特にRust crateを配布するLinuxディストリビューションでは、この問題はさらに大きくなり得る