我以为我在构建C的替代品。我错了。

Lobsters Hottest 工具

摘要

作者反思了将C3营销为C替代品的错误,讨论了C语言角色的演变以及在某些情况下过程式编程相对于面向对象编程的优势。

<p><a href="https://lobste.rs/s/wpyhdh/i_thought_i_was_building_c_replacement_i">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/08/16 15:56

# 我以为自己在打造C语言的替代品。我错了 原文:https://c3-lang.org/blog/i_thought_i_was_building_a_c_replacement/ https://github.com/c3lang/c3-web/edit/main/docs/blog/posts/I_thought_I_was_building_a_c_replacement.md 推广C3时,我犯了一个相当根本的错误。 我称它为C语言的替代品。 这在我看来似乎是理所当然的。多年来我一直寻找更好的C语言,后来发现了C2(http://www.c2lang.org/)并参与其中,C3最终由此诞生。当然C3就是C语言的替代品。 但我逐渐意识到,“C语言替代品”这个说法在今天所指的含义,与我最初的理解已大相径庭。 原因简单得令人尴尬:我年纪足够大,还记得C语言曾是应用程序开发语言的时代。要理解我错在哪里,我们必须回到上世纪80和90年代。 我最初接触的是BASIC语言,长期以来,汇编和BASIC是主要选择。这正值80年代家用电脑“革命”时期。随着16位家用电脑的出现,更多语言突然变得可行——主要是Pascal和C。 那个年代,对于预算有限的年轻人来说,最难的其实是找到编译器。我甚至不得不用QBasic进行严肃编程,仅仅因为DOS安装时自带了它!后来我……呃……“弄到”了一份Turbo Pascal... 我的Pascal时期效率极高。如果想实现某个功能,只需坐下来编写代码即可。相比使用迷宫般的BASIC `goto`/`gosub`,Pascal非常友好,易于组织。这种组织性并非来自预先规定的结构或架构——毕竟它是过程式语言。 我通过获得GCC学会了C语言基础知识,后来在大学学习了初级C++。此时我写的所有代码都是过程式风格。然后我参加了Java暑期课程,大概是1996年,互联网方兴未艾。 Java将面向对象作为核心方法。 这很新颖,很有趣,尽管我写过C++,但直到那时才真正理解面向对象的意义。由此开启了我对面向对象编程的喜爱。最初并不太需要这个。后来找到C++工作时,我也很少有机会实践面向对象。但让我们快进到后来。 我接触到了Objective-C,在Java游戏服务器的工作让我大量练习快速编写Java代码,但我仍感到一种挥之不去的不满。因为我再也没有体验到早期使用Turbo Pascal时的原始开发速度。我的编程能力更好了,但不知为何却更慢了——写等量代码时需要思考更多设计问题。直到后来长期参与PHP项目开发时,我才真正反思这一点。 那个代码库有点面向对象,但不过度。有趣的是,其核心基本上是: > “用户发起调用,将其路由到该函数执行,并展示这个结果。” 即使内部某些部分被封装在面向对象的类中,整体仍是过程式的。天啊,开发效率极其惊人。 我逐渐明白,面向对象的部分是多余的:整个系统本可以用C语言配合区域分配器+良好的动态数组和字符串来实现。根本不需要面向对象。 这让我开始思考。Turbo Pascal般的开发速度重现了,那为什么面向对象没给我这种体验?我在面向对象编程对前期架构的要求中找到了答案。 在面向对象编程中,你从一开始就需要思考架构——什么对象拥有什么对象,什么对象知道什么对象。面向对象“最佳实践”的很大一部分,比如面向接口编程,实际上都是在试图缓解这种深度耦合的问题。 *方法*从根本上与这个问题相关。当我们写下: ``` foo.bar() ``` 就创建了一个层次结构,其中`foo`的类比`bar`更基础。 在编程中,我们谈论在开发程序时探索问题空间。随着理解加深,我们通常会重构程序使其更易解决问题。 面向对象编程的问题——或者更宽泛地说,“方法优先”的问题——在于前期架构设计和方法的使用抑制了这些改变。当我们把B放在A中时,反转这种关系不仅意味着移动字段:还意味着重写所有依赖它的方法。这让我们不愿进行此类重构,反过来意味着前期做出的糟糕决策往往会被锁定。 这不仅是面向对象的问题,而是任何“方法优先”范式的问题——即当你思考: ``` 对象.方法() ``` 而非: ``` 函数(对象) ``` 后者是过程式思维。前者是“方法优先”。 顺便说一句,C3之所以有方法,是因为它们在避免函数重载方面异常有效(例如`foo.to_string()`)。但这也让人更难摆脱“方法优先”的思维定式。 (在这方面Odin(https://odin-lang.org/)有优势:它从一开始就培养人的良好思维习惯。) 对我来说,一切开始变得清晰。 我的PHP经验表明,创建优秀的抽象从来不需要面向对象部分。而认识到面向对象——或更广义的“方法优先”——让编写具有良好架构的程序变得更困难,这让我更明白自己一直以来追求的是什么。 C语言并不完全符合要求,因为libc极其基础,整体已不具备必要的工程便利性。而C++的子集也不是解决方案。它浸透了“方法优先”思想,最重要的是*编译速度太慢*。 所以没错,我确实在寻找C语言的替代品。 但我真正寻找的是一种具有现代应用程序开发所需工程便利性的C语言替代品。这个区别至关重要。 当我说“C3是给喜欢C的人准备的类C语言”时,我想到的是那些会用C写所有代码的人。比如Sean Barrett(https://nothings.org/)这样的人。 但我逐渐意识到,“类C”或“C替代品”在今天意味着完全不同的东西。它意味着“用于C语言*当今*主要用途的编程语言”。那就是操作系统开发、嵌入式领域,以及高性能利基库和后端。 人们用C写数据库,而不是下一个视频编辑器或游戏。对于后者他们使用C++或类似语言。因为使用C++,你能获得C语言缺乏的额外便利性:动态字符串和数组、映射、一些重载功能。这完全合理。 但这并不是我当时的思考方向。我考虑的是用C语言编写*程序*——通用应用程序。那些人们现在用C++、Objective-C、Swift、Java或Kotlin来构建的东西。 我一直认为C3编写这些应用程序时会同样好用——甚至更好。这并不是因为我想把C3变成另一个C++、另一个Java或另一个Swift。恰恰相反。我想要C语言的原始简洁性和性能,同时具备构建现代软件所需的工程便利性。就是一种你选来完成任务的语言,有足够的便利性让过程尽可能愉快方便。 在当今大多数程序员眼中,这*不是*他们联想到的C语言。但这曾是我对C语言的理解,因为我年纪足够大,还记得这确实是C语言的时代角色。 (这也是为什么Zig的决策与C3如此不同:Zig的主要目标似乎是取代C语言*当今*的用途。) 当人们问“为什么有人想取代C语言?”时,我错误地总是理解为: > “C语言已经够好了,我们不需要替代品。” 但他们真正的意思是: > “C语言已不用于任何有趣的项目,何必费心寻找替代品?” 这就是我误解讨论的地方。我在一个C语言意味着其他东西的世界里,使用着过时的“C替代品”定义。因此当我将C3作为C语言替代品推广时,我犯了一个相当根本的错误。 C3始终是C、C++乃至Swift等语言的替代品。——我只是没有充分思考世界已经发生了多大变化。这也改变了我谈论C3的方式。 因此未来,C3将少谈“类C”特性,多谈它作为构建通用应用程序的编程语言的定位。因为其核心目标一直是: **复兴C语言,使其再次成为令人愉悦的通用应用程序语言。** 换句话说,我花了多年时间将C3作为C语言替代品推广,但我真正试图构建的是更广阔的东西。 只是我错误地进行了市场定位。 --- 在Reddit (https://www.reddit.com/r/programming/s/YQLHFmUgqK)、Lobste.rs (https://lobste.rs/s/wpyhdh/i_thought_i_was_building_c_replacement_i) 或HackerNews (https://news.ycombinator.com/item?id=49320169)上讨论这篇博客文章。

相似文章

反对C语言替代方案的理由(2022)

Hacker News Top

本文反对用替代方案取代C编程语言,并强调了工具链成熟度、语言不确定性、开发者资源有限性和C ABI兼容性问题等挑战。

C 并非低级语言 (2018)

Hacker News Top

这篇文章论证了 C 编程语言并非真正的低级语言,挑战了普遍观念,并讨论了其抽象和设计。

写给 Rust 程序员的 C 语言

Lobsters Hottest

一篇由 Rust 程序员撰写的博文,记录了其自学 C 语言过程中遇到的各种奇特行为,包括通过 <stdbool.h> 实现布尔类型、以 null 结尾的字符串与 Rust 中长度前缀的 &str 之间的对比,以及相关的内存权衡。对于从 Rust 转向 C 的开发者来说,它是一份实用的配套指南。