C 語言才是最佳選擇 (★ 131 分)
SQLite 自 2000 年開始以通用 C 語言實作,作者認為對「像 SQLite 這種被大量呼叫的底層函式庫」而言,C 仍是最合適的選擇,現階段也沒有改寫成其他語言的計畫。文章把理由歸納為四點:效能、相容性、低相依性與穩定性,並強調 SQLite 的目標是「小、快、可靠」,而這類資料庫引擎本身就已經夠難,不該再讓實作語言的規格與生態快速變動增加風險。
在效能上,C 常被形容為「可攜式組合語言(portable assembly language)」,能更貼近硬體、同時維持跨平台可攜性;其他語言頂多宣稱「跟 C 一樣快」,但很少有人宣稱能在通用場景全面超越 C。相容性方面,幾乎所有平台與語言都能呼叫 C 函式庫;若當年 SQLite 用 Java 寫,Android 也許更順,但 iPhone 端的 Objective-C 或 Swift 無法直接呼叫 Java 函式庫,反而會讓 SQLite 失去關鍵的跨平台價值。低相依性則是 SQLite 的核心訴求之一:最小組態只依賴標準 C 函式庫的少數記憶體與字串例程(如 memcmp、memcpy、strlen 等),完整建置也只再加上 malloc/free 與檔案 I/O 介面;相對地,許多「現代語言」往往得帶著龐大的執行期(runtime)。至於穩定性,作者直言 C「老又無聊」,但正因為大家熟、規格變動慢,才適合用來打造需要長年維護的嵌入式資料庫引擎。
文章也回應兩類常見質疑。第一是「為何不用物件導向語言」:作者指出 C++/Java 的函式庫多半較容易被同語言世界使用;而「物件導向(Object-Oriented)」是一種設計方法,不等於只能靠特定語言才能做到,C 也能用結構化方式達成類似效果;此外,物件導向並非永遠最佳拆解手段,程序式(procedural)在可讀性、維護性與效能上常更直接。第二是「為何不用安全語言」:像 Rust、Go 這類主打記憶體安全的語言在 SQLite 前 10 年根本不存在;全面改寫可能引入更多錯誤甚至變慢。作者還提出幾個 SQLite 特有的品質策略考量:安全語言常加入額外分支做邊界檢查,讓機器碼難以做到 100% 分支覆蓋測試(branch coverage),而 SQLite 很重視這件事;另外許多安全語言在 OOM(Out-Of-Memory,記憶體不足)時傾向直接中止,但 SQLite 設計為可在 OOM 下「優雅復原」。文末雖不排除未來改用 Rust,但列出一系列前提:Rust 必須更成熟、ABI(Application Binary Interface,二進位介面)與跨語言呼叫更通用、能支援沒有作業系統的嵌入式平台、測試工具能達成 100% 分支覆蓋、具備 OOM 復原機制且效能不明顯輸給 C。
Hacker News 討論多數同意「SQLite 用 C 很合理」,理由集中在:C 在各種「冷門、奇特平台」的編譯器可得性、工具鏈與靜態分析工具的深度,短期內很難有其他語言匹敵;也有人提到 SQLite 以大量測試著稱,測試碼規模遠超本體,這種品質流程與「可做到完整分支覆蓋」的要求,確實偏向 C 這類可精準控制輸出機器碼的語言。也有讀者對文章內個別論點提出修正:例如「C++ 函式庫只能給 C++ 用」被認為過度簡化,實務上常以 C API 包裝 C++ 內部實作來提供跨語言呼叫,但代價是介面設計需避開 template(範本)、move semantics(移動語意)等跨語言難以暴露的特性,等於犧牲部分 C++ 的表達力。
關於「安全語言」的爭點,討論區最聚焦的是 OOM 行為:有人引用 Linus Torvalds 對 Linux 核心導入 Rust 時同樣關切「配置失敗要能回傳錯誤而非直接崩潰」;也有人反駁文章把 Rust/Go 一概而論,指出 Rust 的語言特性本身不必然會配置記憶體,且可用 `no_std`(不使用標準函式庫)或 `core` 來做嵌入式與核心層用途,但標準函式庫確實仍有不少介面可能 panic(類似不可復原的中止),這跟 SQLite 的設計哲學會衝突。另有讀者補充「Rust 重寫 SQLite」其實已在民間進行(如 Turso/Limbo),比較像相容專案而非原團隊的改寫;整體風向偏向務實:若現有 C 版本已高度可靠且可在大量平台部署,除非有明確目標(例如安全漏洞壓力、平台限制或功能需求)否則重寫未必划算,短期更可能換來更多新錯誤。
👥 108 則討論、評論 💬
https://news.ycombinator.com/item?id=46511470