ハクソク

世界を動かす技術を、日本語で。

Cが最高です

概要

  • SQLiteはC言語で実装されている理由の解説
  • パフォーマンス・互換性・依存性の低さ・安定性が主な理由
  • オブジェクト指向言語や「安全な」言語で実装しない理由も説明
  • Rustなど新しい言語への移行条件も記載
  • 今後もC言語での開発継続予定

SQLiteがCで実装されている理由

  • C言語はSQLiteのようなソフトウェアライブラリ実装に最適
  • 2000年5月29日から一貫して汎用Cで実装
  • 他言語への移行計画なし

主な理由

  • パフォーマンス

    • 頻繁に利用される低レベルライブラリには高速性が必須
    • Cは「移植可能なアセンブリ言語」と評される
    • 他の言語も「C並みの速さ」とは言うが、「Cより速い」とは主張しない
  • 互換性

    • ほぼ全てのシステムがCで書かれたライブラリを呼び出し可能
    • Javaで書かれた場合、Androidでは便利でもiPhoneでは利用不可
    • Cで書くことで多様なプラットフォーム対応が可能
  • 依存性の低さ

    • Cで書かれたライブラリはランタイム依存が非常に少ない
    • SQLiteの最小構成で必要な標準Cライブラリ関数はごくわずか
    • 他のモダン言語は巨大なランタイム依存や多数のインターフェースが必要
  • 安定性

    • Cは「古くて退屈」な言語であり、仕様や挙動が安定
    • 実装言語の仕様変更リスクが少なく、信頼性重視の開発に最適

なぜオブジェクト指向言語で実装しないのか

  • C++やJavaで書かれたライブラリは同言語以外からの利用が困難
  • Cならどんな言語からも呼び出し可能
  • オブジェクト指向は設計パターンであり、Cでも実現可能
  • オブジェクト指向だけが最良の設計手法ではない
  • SQLite開発当時、Javaは未熟、C++は互換性問題が多発
  • 現在も他言語への移行メリットはほぼなし

なぜ「安全な」言語で実装しないのか

  • RustやGoなどの「安全な言語」はSQLite誕生から10年以上存在しなかった
  • 安全な言語での再実装は新たなバグやパフォーマンス低下リスク
  • 安全な言語は実行時検証による分岐追加があり、完全なテストが困難
  • SQLiteはメモリ不足時も優雅に復旧する設計だが、安全な言語は通常abort
  • Rustのような新言語は成熟・安定・移植性・ツール類がまだ十分でない
  • Goは**assert()**の扱いがSQLiteの方針と合わないため移行は非現実的

Rustへの移行のための条件

  • Rustの成熟度・安定性の向上

  • 他言語からの汎用ライブラリ呼び出し実現

  • 組込み機器やOS非搭載デバイスでの動作実績

  • 100%分岐カバレッジテスト対応ツールの整備

  • OOM(メモリ不足)時の優雅な復旧機構の実装

  • C並みの速度でSQLiteの処理を実現できること

  • Rustコミュニティからの提案や働きかけも歓迎

まとめ

  • SQLiteはC言語による実装を今後も継続予定
  • パフォーマンス・互換性・安定性・依存性の低さを重視
  • 新言語への移行は慎重に検討される方針

Hackerたちの意見

> Rustには、OOMエラーから優雅に回復するためのメカニズムが必要だよね。Linusもこれについて言及してたし。https://lkml.org/lkml/2021/4/14/1099
彼の言ってることは間違ってないけど、もうちょっと自分のところを整理した方がいいね。
Rustの言語機能はどれもメモリを割り当てないよ。配列も、クロージャも、イテレータもね。デフォルトではすべてスタックに割り当てられる。Rustのコードは、mallocを呼び出すライブラリを使わない限り、mallocしないんだ。つまり、Cと全く同じ。Rustはメモリ割り当てを行う標準ライブラリの部分をオフにすることを完全にサポートしていて、これがまさに組み込みコードやLinuxカーネルがやってることなんだ。だから、Rustはすでに完全なコントロールを提供してるよ。
この文章の最後のコメントは冷静で、変化に対するオープンさを示してるね。最近、RediSearchをRustに移行するプロジェクトに取り組んでたんだけど、これは最近のCVEsが結構あったからなんだ。SQLiteがこの問題を抱えてないなら、Rustに移行するための他の強い理由が必要だと思う。Rustが得意な範囲を理解するには、かなりの時間がかかると思うし、数十年かかるかもしれないね。例えば、個人的にはRustがGUIアプリケーションにどれだけ向いてるのかはよく分からないな。
C以外の言語を使うというアイデアをすぐに却下しないのはいいね(結論は、ここにある編集されたタイトルが示唆するほどドグマ的ではないし、実際のページのタイトルは「SQLiteはなぜCで書かれているのか?」だから)。でも、Cが今享受している安定性や「退屈さ」は、実際に数十年かけて実現されたものだってことははっきりさせておこう(ANSI C以前は、ECMAのJavascriptと比べても野蛮な状況だった)。他の言語にも同じ自由度を与えると、少なくとも2040年まではRustを使うことはないんじゃないかな。
SQLiteのようなものには、Ada/SPARKの方が良い選択かもしれないね。
2017年には少なくとも[1]だけど、「このページは2025-05-09 15:56:17Zに最終更新されました。」 [1] https://web.archive.org/web/20170701061906/https://sqlite.or...
もっと更新されると思うよ。
スティーブ・イェッゲがガスタウンを解き放って、コンボイかなんかでSQLiteをRustで書き直してほしいな。もちろん100%のテストカバレッジは維持してね。結果は成功するか失敗するかに関わらず、間違いなく衝撃的なものになると思う。
どのプロジェクトやプログラマーも、Rust(またはZig)を使わない選択を正当化しなきゃいけないなんて思う必要はないよ。特にHacker Newsや特定のSNSで不自然に押されてる感じがするからね。最近は少し減ったけど、OOPを使うプレッシャーもあったし。もしCでOOPなしで良い結果を出していて、みんながその製品を気に入っているなら、外部の人がそのプロジェクトに口を出すべきじゃないと思う。それは彼らのプロジェクトなんだから。
TidesDBについては、これをよく聞かれるんだ。「なんでRustを選ばなかったの?」って。まあ、これは本当に一般的な質問だね。いいコメントだ。
我々(特に経営陣)は、常に新しいものを求めるように訓練されているんだ。それに、簡単なセリフでもあるしね。
すべての面で優れていて、デフォルトでコードをバグが少なくするツールが、使っているほとんどの人から称賛されるのは不思議じゃないよね。「電動ドリルが、昔ながらの手動のオーガーよりもHome Depotで異常に推されている」なんて言うのはおかしいし、たとえ君の契約会社で働いていなくても、君がうちの家で作業するのはちょっと不安になるよ。
> Hacker Newsで不思議に思われているけど、実際には何も不思議じゃないし、不均衡でもないよ。新しい言語は、古い言語に不満を持った人たちがデザインしたもので、技術の新しい応用に興味があるグループには当然関心があるんだ。 > プロジェクト外の人はあまり口出ししない方がいいね。彼らのプロジェクトなんだから。プロジェクト外の人は何を言ってもいいけど、プロジェクト側がそれに耳を傾ける必要はないよ。
そうだね、結果が全てだよ。SQLiteのプロセスは、しっかりしたバグのない結果を出しているみたい。唯一の不満は、使いたいSQLの機能がサポートされていないことかな。確かに、その一部は意図的に制限された範囲かもしれないけど、開発のスピードの問題もあるかもしれない。DuckDB(C++)は、もっと多くのSQL機能を持つSQLiteのように使えるけど、バグが多いんだ。データベースからのセグメンテーションフォルトは避けたいよね。だから、何か代替案が出てくるのを期待してる(もしくは自分で書く必要があるかも)。
OOPはいつも議論の余地があったけど、AIエージェントの台頭で今は客観的に悪いと言えると思う。AIは命令型のクラスと継承よりも、純粋な関数文法を推論するのがずっと得意だし、完全でない抽象はバグの温床になる。
大体同意だけど、OOPは少なくとも過去10年、HNでは明らかに流行ってないし、もっと長い間そうだったと思う(Rustの1.0以前やGoの1.0の頃を考えてみて)。
背景として、プロジェクトを新しいものに移行する圧力が常にある中で、Cや他のメモリ安全でない言語に対する反発もかなり強いよね。最近、アメリカ政府がみんなにそれらを使うのをやめて、メモリ安全な言語に移行するよう呼びかけたんだ。とはいえ、安全なCコードを生産するための実践やツールもあって、Cプログラマーにそれを教える努力をもっとすべきだと思う。
Rustの設計は理論的には興味深いし、最近のLinuxカーネルのRustコードのバグ(Androidで使われるメッセージパッシングの抽象化)も示してるけど、以下のことが明らかだよね。1. Rustを使うことでリスクは減らせるけど、同じ種類のバグは残るし、もちろんメモリに関係ないバグもある。2. Cを使えば、レースコンディションに対する感覚を養うことができて、注意を払うことができる。一般的に、Cプログラマーは「バグアンテナ」が他の人よりも発達してるかもしれない。3. Rustでは「unsafe」な部分を減らすために、時にはちょっと不自然な抽象化を作る必要がある。4. Rustは偽の安全感を生むことがあって、unsafeな部分ではプログラマーが時々、必須のSAFETYコメントによって誤解を招くことがある。Linuxカーネルのバグのように、そのコメントが人間によって幻覚のように見えたこともあるし、(この特定のケースではどうかわからないけど、あくまで例ね)Cが教えてくれる「レーススポッティング」のプロセスに慣れてない場合もある。5. Rustでバグが発生した場合、修正はCのように一行で済むことは少なくなり、露出時間が長くなることがある。Rustでの修正は、時には非自明な方法でリファクタリングを意味する。6. Cの場合、カーネルプログラミングを安全にするためのラッパーを作るのに同じだけの努力をすれば、攻撃面をかなり減らせる可能性がある(例えばRedisのsds.cを見てみて、どれだけ直接的な文字列やポインタの操作を避けてるか)。基本的に、sds.cのようなものは、unsafeな部分を自己完結型のライブラリにまとめることができる。だから、Rustは特定の機能において面白い言語かもしれないけど、銀の弾丸ではない。だから、Rustを他の人に「押し付ける」べきか?絶対にNOだし、Rustを無理に採用するようにプレッシャーをかけてくる人には、しっかりと返事することをおすすめする。
どんな真剣なプロジェクトでも、ツールの選択を正当化できるべきだよ。「なんとなく」っていうのは趣味のプロジェクトやオープンソースの情熱プロジェクトにはいいけど、商用ソフトウェアには選択の理由が必要だよね。その理由は「私たちがよく知っているから、最も効果的」みたいなものであっても、意図的で計画的な選択であるべきだ。SQLiteは非常に高品質なソフトウェアプロジェクトの一例だよ。それはソフトウェア自体の品質だけでなく、その周りのプロジェクト管理も含まれる。さまざまな設計選択を説明することも含まれていて、この言語選択を説明する文書は、その説明の一つに過ぎない。
> Rustはもう少し成熟して、あまり急激に変わらず、古くて退屈な方向に進むべきだと思う。Cの非常に奇妙な点の一つは、保守的な委員会によって設計されていて、新しい機能を追加することを好まないことだ。特に互換性を壊す可能性がある場合はね。Rustが古くて退屈な言語になる前には、こういうのが必要だと思う。でも、Rustがそんな方向に進むとは思えない。Rustの哲学、つまり解決しようとしている問題に対して最良の解決策を見つけることが根本的に反対しているように感じる。互換性を壊すことも含めて、どんなコストをかけても。
あれれ!Rustは最終的には落ち着くかもしれないね。誰が知ってるか、もしかしたら開発者の誰かがコメントするかも。
「ある程度」というのは結構重要だよ。Rust言語は時々後方互換性のない変更を受けるけど、Rustのツールはそうじゃない。2024年版は2021年版からの破壊的な変更があるけど、すべてのコンパイラは歴史的なすべての版をコンパイルできて、これからもずっとそうだし、新しい言語機能はできるだけ多くの版で利用できるようになってる。依存関係のツリーの中で版を混ぜることもできるから、2015年版のコードを何かのために更新する必要は全くないんだ。
> Rustの哲学、つまり解決しようとしている問題に対して最良の解決策を見つけることが、どんなコストをかけても、互換性を壊すことも含めて、ある程度はね。でも、Rustチームは後方互換性を壊さない素晴らしい方法を見つけたんだ。古いコードは古いバージョンのコンパイラで自動的にコンパイルされて、新しいコードは最新のコンパイラで処理される。これは、C++の人たちが苦労しているように、古い荷物を持ち運ぶよりもずっと良いと思う。
Cが保守的で物事を壊したくないから「不思議」と呼ぶのはちょっと変だね。それはその意味では「偉大な」ことの一つだし。「安定している」っていうのも別の表現かも。
自分はかなり真剣な「Rustacean」だけど、「正しい理由」でそう思ってる。メインプロジェクトをRustで書き直すのは、Cでは達成できない目標がない限り、あまり意味がないと思う。この人は、特に最後のセクションで、書き直すのがあまり意味がない理由をよく考えて提示してる。Rustは多くのことに優れてるけど、すでにテストが十分に行われていて、いろんなマイナーなプラットフォームでアクセス可能な古いものを持っている場合、書き直すのはあまり意味がないし、短期的にはバグが増える可能性が高いと思う。とはいえ、Rustで書き直す理由を見つけて、現在取り組んでいる人たちもいるよね:https://turso.tech/blog/introducing-limbo-a-complete-rewrite...
うん、同意する。Limboがどうなるか楽しみだね :)
正直言って、SQLiteをRustに移植するよりも、まずは使いやすい埋め込みデータベース(Rustで)を作る方が理にかなってると思う。
お、何かが動いてる。壊さないようにしようよ?それってすごくクレイジーだよね?時々、こういうことが起こるのかなって考える。1. 問題がある。より高レベルのプログラミング言語が必要。2. 問題について考える。3. 問題を解決する - 'C' 4. 'C'の問題について考える 5. 'C'の問題を解決しようとする - C++ができる 6. CとC++の問題について考える 7. Go、F#、Rust、Java、JavaScript、Python、PHP、...その他が出てくる。こういう風に進むことが多い。問題は明らかで、ステップ#2を繰り返さないことなんだ。だから次のステップに進む。8. C、C++、Go、F#、Rust、Java、JavaScript、Python、PHP、...その他をどうやって修正するか考えるのは難しすぎる。9. 考えるのをやめる。
MozillaがRustの研究開発にお金を払った理由はC++の問題だったけど、Rust(ましてやF#)をそれらの問題を特に解決するための試みとして考えるのはあまり役に立たないかも。Cは「悪い方が良い」言語(https://en.wikipedia.org/wiki/Worse_is_better)だよ。実装が簡単なら、実装しているものが素晴らしくないことはその実装の簡単さにかき消されるっていう賭けなんだ。これが数十年も成功してきたのは間違いなく成功だよ。Goについても似たようなことが言えるけど、Rustにはあまり当てはまらない。悪い方が良いの反対側は、もしかしたら「正しいこと」を作ることができるかもしれないってこと。Cの実装が簡単で、「正しいこと」を実装するのが非常に難しいから、これが競争するためには、ほとんど誰も「正しいこと」を自分で実装する必要がない場合だけだ。1970年にはそれはクレイジーだったけど、1995年には「そんなことない」って感じになってきた。Intelのx86 ISAがどこにでもあって、Timのクソみたいなハイパーメディア実験が本当に盛り上がってきた。2015年にRust 1.0が出たときには、多くの人が実装作業なしで使えるようになって、「正しいこと」がただ良いものだから、なんで使わないの?今、既存の成功したプロジェクトに関しては計算が全然違うけど、FishはこのRIIRがうまくいってる例だと思う。ただ、新しい作業にCを使うべきかどうかについては、私の意見では、かなりのCプログラマーとして、Rustの方がいいからCには反対だね。
外部者としてRustについて読むと、すでに動いているものを再構築するための言語として位置づけられているように感じる。言語の最初の印象としては単純すぎるけど、GoはKubernetesやクラウド、ネットサーバー用の言語、RubyはRails用、JSはブラウザやブートキャンプ用の言語、PythonはデータサイエンスやAI用って感じがする。もちろん、安全性は得られるけど、古い(そしてメンテナンスされている)コードベースの安定性を失うことになるかもしれない。もしかしたら、Rustは「再構築の言語」以上のものとして自分を位置づける時期かもしれないね。
Cを直接書くことが、Dafnyのような言語を使ってCコードを生成するよりも良いなんて想像できないよ。編集: Dafny: 不変条件を強制できる検証言語
まあ、反論できないね。RubyやPythonは、基本的にはCで書かれてるし。みんなCを置き換えようとしたけど、結局失敗してる。高い要求にも低い要求にも応えられる言語があればいいなと思うけど、どんな感じになるかは全然想像つかないな。