C是最好的选择
注意:本文的第2.0和3.0部分是根据Hacker News和Reddit上的评论添加的。
自2000年5月29日创建以来,SQLite一直以通用C实现。C是实现类似SQLite这样的软件库的最佳语言,而且目前没有在任何其他编程语言中重新编写SQLite的计划。
实现SQLite选择C语言的原因包括:
1. 性能
像SQLite这样强烈使用的低级库需要快速响应。(而SQLite是快速的,详见内部与外部BLOBs和比文件系统快35%等)。
C是编写高效代码的绝佳语言。C有时被描述为"可移植汇编语言"。它使开发人员能够尽可能地接近底层硬件编码,同时仍保持跨平台移植性。
其他编程语言有时声称"和C一样快"。但没有其他语言声称在通用编程方面比C更快,因为确实如此。
1.1. 兼容性
几乎所有系统都能调用用C编写的库。其他实现语言则不一定具备这个特性。
例如,使用Java编写的Android应用程序可以调用SQLite(通过适配器)。也许如果SQLite是用Java编写的,对于Android来说可能更方便,因为这样界面会更简单。然而,在iPhone上,应用程序是用Objective-C或Swift编写的,这两种语言都无法调用用Java编写的库。因此,如果SQLite是用Java编写的,它将无法在iPhone上使用。
1.2. 低依赖性
用C编写的库没有庞大的运行时依赖。在其最小配置中,SQLite仅需要标准C库中的以下例程:
- memcmp()
- memcpy()
- memmove()
- memset()
- strcmp()
- strlen()
- strncmp()
在更完整的构建中,SQLite还使用诸如malloc()和free()之类的库例程,以及打开、读取、写入和关闭文件的操作系统接口。但即使如此,依赖的数量也很小。相比之下,其他"现代"语言通常需要加载成千上万个接口的多兆字节运行时。
1.3. 稳定性
C语言具有悠久而稳定的历史。这是一个众所周知且被充分理解的语言。这正是开发类似SQLite这样的模块时所希望的。编写一个小巧、快速和可靠的数据库引擎已经足够困难了,如果在实现语言规范的每次更新时,实现语言发生了变化,那将使事情变得更加困难。
2. 为什么不用面向对象的语言编写SQLite?
一些程序员无法想象在非"面向对象"的语言中开发诸如SQLite之类的复杂系统。那么为什么SQLite不用C++或Java编写呢?
用C++或Java编写的库通常只能被用相同语言编写的应用程序使用。很难让用Haskell或Java编写的应用程序调用用C++编写的库。另一方面,用C编写的库可以被任何编程语言调用。
面向对象是一种设计模式,而不是一种编程语言。你可以在任何想要的语言中进行面向对象编程,包括汇编语言。一些语言(如C++或Java)使面向对象编程更容易。但你仍然可以在C等语言中进行面向对象编程。
面向对象不是唯一有效的设计模式。许多程序员被教导要纯粹以对象为思考方式。公平地说,对象通常是分解问题的一种良好方式。但对象不是唯一的方式,也不总是分解问题的最佳方式。有时,良好的传统过程代码比面向对象代码更容易编写、更容易维护和理解,而且更快。
当SQLite首次开发时,Java还是一种年轻且不成熟的语言。C++更老,但正经历着艰难时期,很难找到两个C++编译器的工作方式完全相同。因此,在SQLite首次开发时,C无疑是更好的选择。现在情况不那么严重了,但在这一点上重新编码SQLite几乎没有好处。
3. 为什么不用"安全"语言编写SQLite?
最近对"安全"编程语言(如Rust或Go)产生了很多兴趣,这些语言中不可能或至少很难出现常见的编程错误,如内存泄漏或数组越界。因此,经常出现的问题是为什么SQLite不用"安全"语言编写。
在SQLite的前10年历史中,没有任何安全编程语言存在。SQLite可以重新用Go或Rust编写,但这样做可能会引入比修复的错误更多的错误,并且也可能导致代码变慢。
安全语言会插入额外的机器分支来验证数组访问是否在边界内。在正确的代码中,这些分支永远不会被执行。这意味着机器代码无法进行100%的分支测试,这是SQLite质量策略的重要组成部分。
安全语
言通常希望在遇到内存耗尽(OOM)情况时中止。SQLite被设计为从OOM中优雅地恢复过来。目前这在当前的安全语言中可能无法实现。
所有现有的安全语言都是新的。SQLite的开发人员赞赏计算机语言研究人员努力开发更容易安全编程的语言。我们鼓励这些努力继续进行。但在实现SQLite时,我们更感兴趣于传统且稳定的老语言。
尽管如此,有可能有一天SQLite会用Rust重新编写。在将SQLite重新编写为Rust之前,必须满足以下一些先决条件:
- Rust需要再成熟一些,停止快速变化,并朝着老旧和稳定的方向发展。
- Rust需要证明可以用于创建可从所有其他编程语言调用的通用库。
- Rust需要证明能够生成适用于包括没有操作系统的奇怪嵌入式设备在内的设备的目标代码。
- Rust需要提供必要的工具,以便对编译后的二进制文件进行100%的分支覆盖测试。
- Rust需要一种机制来优雅地从OOM错误中恢复。
- Rust需要证明能够在不显著降低速度的情况下完成SQLite在C中的工作。
如果你是Rust的支持者,并且认为Rust已经满足了上述条件,并且应该用Rust重新编写SQLite,那么欢迎并鼓励你私下联系SQLite的开发人员,并论述你的理由。