本文根据 tmp.0ut 第五期中 tmp.0ut Staff 的文章编译整理,非逐字翻译;文中观点均属于原作者。
文章内容来自 tmpout.sh,本译文依原站 CC BY-NC-SA 4.0 许可作为改编内容发布。如有侵权请通知,我会下架文章。 全文字符数:10458
收听文章
一场在 Dartmouth 的访谈
2025 年 10 月,tmp.0ut 团队在达特茅斯学院(Dartmouth College)的计算机科学实验室采访了 Doug McIlroy。这场访谈是“Binary Fun Week”系列活动的一部分——围绕文件格式、恶意软件、逆向工程、漏洞利用与 Binary Golf 的一周系列讲座。现场除了几位演讲者,还有参与提问的学生。
McIlroy 1932 年出生,是 Unix 与 C 语言形成时期就在场的亲历者,参与过许多我们今天仍在使用的核心工具和语言。访谈导语写道,他的设计方法建立在对代码及其文档的细致研究之上;他一生都在琢磨“下一步是什么”,追求用更少的东西做更多的事。他还被引述过一句名言:“编程真正的英雄,是写负代码的人。”(negative code)
echo、sort 与早期 C 程序
采访从“所以你写过 echo?”开始。McIlroy 说 echo 是他写的第一个 C 程序,时间大约在 1972 年、C 语言刚诞生不久;他当时完全没想到它后来会如此有名。
谈话还提到他参与过的程序清单:diff、sort。McIlroy 澄清 sort 最初由 Ken Thompson 写成,而他补上了大部分选项——尽管他本人反对像 ls 那样堆满选项(连大小写都要各占一套旗标)。sort 的手册里曾有一条有趣的说明:“提供宽泛的选项(wide options are available)”,却没有说明这些选项到底是什么。他问 Ken:“那它们是什么?”Ken 回答:“你只要去把它们加进源码就行了。”于是他真的去加了。原页编者在这里配了一个玩笑式的旗标 ls -transubstantiationalist。
与 Ken 和 Dennis 共事
谈及在贝尔实验室与 Ken Thompson、Dennis Ritchie 共事的岁月,McIlroy 说:“他们非常出色。”他认为 Ken 是他认识的最伟大的编程天才之一:不仅做出 Unix,还造出第一台达到大师等级(master rated)的国际象棋机器,其架构后来被 Deep Blue 借鉴并做成芯片,战胜卡斯帕罗夫的就是它。Ken 还受世界冠军(或前世界冠军)Botvinnik 之邀,把机器带去苏联做过展示。McIlroy 自己并不关注棋讯。
从 Cornell 到 MIT:Whirlwind 与“边际测试”
McIlroy 在 Cornell 读工程物理本科。当时 Cornell 想开风气之先,把工科本科生的学制设为五年,这个实验大约持续了十年便告终——毕竟 MIT 四年就能拿到更便宜的学位。他随后去 MIT 深造,主要原因是那里有 Whirlwind 2。
Whirlwind 2 是 1950 年代初的巨型机器,占据一栋楼的三层:地下室是交直流转换用的旋转设备,一层是电子电源,二层才是计算机本体——人可以走进主机内部。累加器的 16 个位,每一位都是一座八英尺高的继电器架;远处是它的两大创新之一——磁芯存储器(core memory),只有一个继电器架大小。Cornell 那台机器只有 24 个字的内存,甚至不是存储程序式的;小一些的型号则有一千个 16 位字(2K)。
项目主管 Jay Forrester 曾告诉 McIlroy,他觉得自己最伟大的发明是“边际测试”(marginal testing):每天开工前,机器要停机一小时做预防性维护,期间把电压反复拉高拉低——如果有什么要坏,就让它坏在测试时段,而不是白天工作的时候。McIlroy 说这就像压力测试。他也见过贝尔实验室的继电器计算机,但从未真正使用过。
他在 MIT 拿的是数学学位,博士论文研究锥壳(conical shells)。他自嘲这个题目“真的很无聊”——本质是研究一片金属锥板弯折时会怎样弯,非常经典。他选它只是为了拿学位,去 MIT 的真正原因是计算机。
他还讲了一段与数值分析擦肩而过的往事:1948/49 年前后,von Neumann 与 Goldstine 发表论文,讨论矩阵求逆需要保留多少位数字,估计非常悲观——10×10 的矩阵或许需要 40 位十进制数字,而当时所有人都在用 8 位数字做同样的事。“如果 von Neumann 和 Goldstine 都估不准,我还有什么机会?”于是他放弃了数值分析。直到 1979 年 Wilkinson 在英国提出反向误差分析(backward error analysis),人们才真正能对数值计算的精度做出可靠估计——“我进入这个领域太早了。”
进入贝尔实验室:宏、PL/1、TMG 与 Multics
McIlroy 1958 年加入贝尔实验室。MIT 的招聘人员出现时,他已经做好准备、非常想加入。在贝尔实验室,博士入职后通常要自己摸索该做什么。他先玩了一阵整数线性规划,结果证明了一个错误定理;IBM 的 Gomory 后来证明了正确的版本,还特意打电话告诉他。
之后他转向宏处理。宏在贝尔实验室流行到这样的程度:做电话交换系统的部门干脆发明了一门完全由宏组成的“编程语言”并重度依赖它。该部门主管曾对他说:“我们是贝尔实验室最大的计算用户,用的机时比谁都多,也比谁都依赖计算。”原因恰恰是宏处理器比普通编译器慢约一百倍。McIlroy 的评价是:宏很适合用来定义一门语言,但一旦定义出来,就该为它写个编译器。
Multics 始于 1964 年,从挑选硬件开始。McIlroy 当时在 PL/1 设计委员会,负责让 PL/1 具备足够能力,看起来像一门配得上书写系统的语言——当时可选的候选语言几乎都是“雾件”(vaporware)。他们与加州一家很擅长 Fortran 编译器的公司 Digitech 签了合同,Digitech 以为能借此在一门新语言里抢占先机;结果对方派了个无人监督的新手,真正懂编译器的人又没盯住,一年后 Multics 仍然没有编译器可用。
于是 Bob Morris 和他决定用 TMG 写编译器。TMG 是 Bob McClure 在德州仪器写出的“编译器书写语言”,原本面向 CDC 1620(36 位机器),再由 McClure 手工转写到 IBM 704/7090 的机器码。McIlroy 回忆那是一次有趣的排错经历:程序逻辑是对的,但 CAL 与 CLA 这类操作码极易在手抄时搞混,调试几乎全在找笔误。他们用 TMG 几个月就写出了 Multics 的第一个编译器,一直用到约 1970 年 GE 拿出真正的编译器为止。开发时那台 GE 645 就在“阁楼”里,三个人埋头苦干;MIT 是 Multics 的主要推动者,还让他们用自己的分时系统。TMG 编译器编译时间长,而 MIT 的调度偏爱短作业——长作业总在故障间隙里运行、常常要跑两遍,McIlroy 说他们“真的把 MIT 的计算中心搅得一团糟”。
Multics 拖了很久没有结果,贝尔实验室高层最终决定止损:那台机器每年约一百万美元租金,却只支撑三个人。说到这里他自己打住:“Multics 的事就讲这么多吧。”
那段时期他还做过大量咨询工作,与 Dick Hamming 共事过。访谈者问:“和 Hamming 一起工作时,你会保持距离吗?”他答:“会。”——Hamming distance 的双关。
PDP-7 上的三周与用户态 shell
Ken Thompson 一直在背后琢磨“小型机”的想法。Multics 被砍后,Thompson、Ritchie 和 Joe Ossanna 力主继续做操作系统,但“一朝被蛇咬”的管理层想要一台 PDP-10。最后 Thompson 找到一台被淘汰的 PDP-7,三周内把整个操作系统做了出来——汇编器和操作系统都出自他一人之手:妻子外出度假,他给自己分配一周写汇编器、一周写操作系统、一周写文件系统。
文件系统的设计那时已经想清楚,所以能这么快;操作系统的 API 如此干净,McIlroy 坦言不知道 Ken 是怎么想出来的。Unix 吸收了不少 Multics 的好想法但实现方式完全不同,例如层次文件系统;把 shell 放进用户态也是来自 Multics 的新观念——Dartmouth 的分时系统也把 shell 放进了用户空间,但没有把它当作可替换的程序;而在 Unix 里,真的出现了多个可替换的 shell,今天大家用的 shell 是当年那个 shell 演化出的 Bourne shell 一系。
网络:被 AT&T 冷落的 Sandy Fraser
同一时期,计算机科学部的 Sandy Fraser 是不遗余力的网络布道者、设计者和建造者。McIlroy 说,尽管 Fraser 坚信数字数据与联网才是未来,AT&T 高层却认为“数字数据只占我们业务的 4%,为什么要操心”,Fraser 没得到应得的支持。不过实验室内部机器之间的联网大约从 1972/73 年就开始了,历经三代网络,最终接入 CSNet(Computer Science Net)——它是 ARPANET 与后来的互联网之间的过渡网络,主要连接各高校的计算机系,通过拨号接入,并有一座通往 ARPANET 的桥。McIlroy 记得网络升级到 1200 baud 时“快得刺眼”。他提到 cu(call up)这个工具的出现时间可以作为参照,而他网站上“Research UNIX Reader”的目录可以查到 Unix 各研究版本是从何时开始联网的。
宏时代的调试与极限约束
有学生追问交换机部门的故事:为什么他们把宏当成编程语言用,而不直接写一门语言和一个编译器?McIlroy 说他想不出特别的原因——“只由机器语言组成的大系统该怎么写?人们一般又是怎么写大系统的?”他的看法是:我们确实在写大系统,但许多系统与其说是被干净地设计出来,不如说是被调试出来的(debugged into existence)。
另一个学生问,当年调试宏是否也很困难(今天的 C 预处理器宏依然难调试)。McIlroy 说不记得有什么调试困难——“那你一定是位好调试者”,访谈者接话。他举了个例子:他曾经用宏写过一个 Lisp 编译器,堪称壮观的构造;他记得自己躺在床上、周围铺满纸,两三天后就让它能跑了,宏展开的调用深度常达 50 到 70 层。那是一台会优化的编译器:Bob Morris 看过他生成的目标码后敏锐地指出,“transfer on non-zero 会把累加器清零”——TNZ 指令本身并不改变累加器,但控制流能穿过它继续执行,就说明跳转没有发生,从而可以推断累加器此刻为零;Lisp 程序里充满判零操作,他便利用这条信息把“判空”优化掉。
在只有约 2K 词的时代,程序员偶尔会翻找指令里没被使用的字段,从中挖出一点额外内存;更重要的是,既然每个程序都如此受限,人们根本不会去构思需要大量空间的东西。McIlroy 提到 IBM 360 的第一批 PL/1 编译器是个绝妙的例子:它们被拆成很小的片段,在最小配置上大约要连续跑 60 次覆盖(overlay)才能完成编译;在更大的机器上,整个编译器则可以一次装入内存。
管道的诞生
访谈最核心的话题是管道。McIlroy 确认自己就是管道的发明者。管道出现之前,程序之间靠文件协作:一个程序写文件,下一个程序读文件。他说,当时 Ken 和他都没有意识到“写文件再读文件”与“管道”之间存在本质差别——差别是实时性。想要两个交互式程序配对,管道可以做到,文件做不到,因为必须先写完整个文件才能开始读。
至于设计过程,他的回答是:“没有设计过程。”当时 Ken、Dennis 和 Rudd Canaday 在走廊另一边研究文件系统,他恰好在走廊这一边琢磨“如何把程序组合起来”的记号。难点在于:ls | wc 很直观、没有串联歧义,可一旦 ls 带选项,怎么区分“选项”和“程序串联”?这个问题困扰了他很久。他最终发明了一种记号——不是今天用的竖线,而是多个大于号(有点像位运算的右移)。他为此游说了很长时间,甚至设想过把单元连接成阵列的细胞自动机那样的形态。Ken 一直不肯做,也许是因为那会让系统更复杂;但当他拿出 shell 记号后,Ken 出乎意料地说“我来做”,而且一夜就做完了。系统本来就支持进程间共享缓冲区,Ken 要做的只是把缓冲区里的单一读写指针改成两个指针、每进程一个。当晚他还拉上 Dennis,让大量原本有具名输入输出的程序在“缺少输出文件或输入文件”时自然可以接入管道,一夜之间改了一大批程序。第二天早上他们宣布“能用了”,随后是一场管道演示的狂欢——“看我这个、看我这个”。
McIlroy 觉得最漂亮的是 Joe Ossanna 的玩法:Ossanna 写过 nroff 和 troff(McIlroy 自己写了更早的 roff),他用左右半页交替排版的技巧,再加一个叫 Overlay 的后处理器把成对页面 OR 起来;他宣布现在可以用管道完成同样的事,还能串两个管道做出四栏输出。到那一周结束时,连秘书都在用管道把内容送进行式打印机。
原始手册里对管道的说明因为要解析多个大于号,既丑又难懂,足足占了一页;如今 shell 里对管道的描述只占一小块地方。“这就是它的全部,妙处也在这里——你不用学任何东西。”至于今天用的竖线符号,是 Ken 要去伦敦做 Unix 演讲、不好意思使用那套丑陋记号,临时想出来的;它从此流传下来,这个符号的功劳后来也大多算在了 Ken 头上。
访谈者问起一个管道的边界情形:一条管道里前面的程序以非零状态退出、后面的程序以零退出时,整体状态却可能成功。McIlroy 说:“我想无论结果是什么,都是碰巧发生的。”他们当时只关心功能——把数据尽快从一个程序送到下一个程序。
顺带一提,访谈聊到 NSA 的语言 Pogol(约 1970–72):它的写法是写许多生成未命名文件、再从文件读取的小程序片段,编译时把中间文件优化掉。它比管道更早,但没有管道记号,程序员仍要“假装有文件”。关于 Pogol 的资料极少,只有 Gloria Lambert 1973 年在 POPL 会议上的一篇论文。
ELF、调试器与“printf 就够了”
被问到 a.out、COFF 再到 ELF 的格式演进时,McIlroy 说 ELF 落地时他已在 Unix support group,完全不了解它的设计过程。他举了一个印象深刻的反例:他有一个程序包含 2^15 × 2^15 字节的数组,只初始化了第一个元素,加载却慢得惊人——因为 C 编译器会为整个数组生成初始化数据并写进 ELF。在他看来,ELF 无法表达“数组只初始化一部分、其余保持未初始化”的布局:那唯一被初始化的元素必须与其余元素相邻(数组在内存里必须是一整块),而编译器也没法让 ELF 知道“这两部分数据必须连续”。他总结说,这或许更接近“编译器如何使用 ELF”的问题,通常只能手工处理或在运行时解决;这个十亿字节级的二进制着实让他意外。
调试方面:在 DWARF 出现之前,调试器依赖 C 程序的符号表。McIlroy 认为 Unix 的第一个调试器大概出自 Dennis Ritchie 之手,名叫 db,后来变成 adb(与后来 Android 的 adb 没有关系;访谈者提到 Stephen Bourne 写过一个 Advanced Debugger,他确认了这一点)。当时可以请求整条栈回溯,也可以查看当前栈帧里的元素并逐帧移动。他后来基本不写大程序,于是放弃调试器,改用“重新编译、塞几行 printf”——通常打印单个字符且不带换行,就能得到一条足够定位问题的轨迹。访谈者打趣说,整场访谈里他一直说“不需要调试器,printf 就够了”;McIlroy 澄清,在资源受限的早年他其实是用调试器的,如今可看的东西太多,限制反而让调试更容易。
他讲过的最有趣的 bug 来自 Fortran 2 编译器,涉及一种他此前从未见过、之后也没再见过的编程技巧。IBM 7090 的某些指令有四部分:两个地址(或带偏移的地址)、一个只有三位的操作码和一个只有三位的变址寄存器。随着机器演进,704 能存整个字或一个地址字段,709 能存整个字或其中任一字段,7094 甚至能写操作码或变址寄存器标签——而他唯一见过使用 store tag 的程序,就是有人拿来的一段 computed go-to 代码。那段代码有 74 个分支:去掉一个能跑,加一个也能跑,唯独 74 个不行。当时还没有调试器,这是他唯一一次整晚坐在 7090 控制台前。最后他发现:编译器维护着一张 computed go-to 的地址表,为了让表能“任意增长又不占任意多内存”,实现者把表按 75 个字的页来分页,并计划用 store tag 在 74 个元素之后关掉变址——但只在一处做了,漏了第二处,而他们从没试过恰好 74 个分支的例子。他对自己能找到这个冷门技巧相当得意。
编译器后门、IX 与 Tom Duff 的病毒
关于 Ken Thompson 的“trusting trust”编译器后门,McIlroy 确认 Ken 确实实现过。那个后门差点扩散出去:维护“程序员工作台”的另一个小组想与最新进展保持同步,发现 Ken 主目录里有这个新编译器便拿去用;不知是通过与旧代码 diff 还是比较体积,他们发现它被动过手脚,随即打电话给 Ken——Ken 说“把那东西弄走”。幸好它没有真正传开。
McIlroy 自己与 Jim Reeds 做过一个多级安全 Unix 系统 IX,采用 Bell-LaPadula 模型。他们发现把这个模型“倒过来”看会得到有趣的性质:Bell-LaPadula 本来禁止把高安全级内容读入低安全级内存;如果反过来,禁止把高安全级内容写入低安全级内存,就得到完整性控制。他们在格(lattice)的中间设定起点,向上是隐私控制,向下是完整性控制——更换系统组件时,要用的正是完整性控制。最初他们把起点(floor)设在零;第一次把起点抬到中间并启用时,系统报出安全违规,大概是实现里有处错误,Jim 花了两天排查。随后他接到电话:“我们抓到病毒了!”
病毒从何而来?Tom Duff 几个月前写过 shell 病毒并撰文发表(1987/88 年的 USENIX 期刊上有两篇相关文章,一篇出自 Duff,一篇出自 McIlroy 自己)。Duff 真的实现了病毒,它不幸在实验室网络上传开;Duff 又写了一个清除程序,从一台机器主动触达其他机器把病毒删掉。而 Jim 与 McIlroy 开发 IX 用的是一台断网的独立机器:病毒扩散时机器恰好联网,清除程序运行时又恰好断网,病毒一直藏在机器里而他们毫不知情——直到启用完整性控制,它自己现了形。McIlroy 称之为新系统的一次漂亮胜利,这也是他第一次在真实使用的计算机上见到病毒。Tom Duff 当时就在贝尔实验室工作,后来因与 Thomas Porter 合写的图像合成论文拿到艾美奖——McIlroy 特意说明 alpha channel 并非 Duff 发明,他只是参与其中。
GNU 时代与一场代码剽窃风波
GNU 兴起时 McIlroy 还在贝尔实验室。内部对此反应平淡:那时模仿者已经很多,只要是在重实现前人做过的东西,政策上就无所谓——GNU 除了背负许多政策争论外,并没有特别之处。真正会踩线的是直接抄代码。
他讲了一个例子:波士顿有人售卖一批 Unix 工具“仿制品”,他亲自看过,目标码与源码存在一一对应关系——显然是照抄。恰逢一位专利律师与 DEC 谈交叉许可,DEC 态度强硬:“你们没有我们感兴趣的东西。”律师去赴会时带上了这个案例作为筹码;而 DEC 请来的专家证人,恰好就是那个卖家。会后喝咖啡时,律师把话题引向代码剽窃,说“我公文包里正好有个例子,想看看吗?”他拿出源码与目标码,对方承认“看起来确实出自这份源码”。律师问:“如果我说这份是我们的、那份是你们的,你会感兴趣吗?”第二天那个人就没再出现,此后再也没有纠缠。
喜欢的程序:Speak、tee/tr 与拼写检查
被问及最喜欢自己写的哪个早期 Unix 程序时,McIlroy 先提到 echo,但那只是因为有趣。他认真提到两个:一个是“管道连接”程序,读取一份长长的进程间管道连接清单并逐一建立连接;当时能同时打开的管道数量有限,做起来有挑战,好玩但不实用。另一个是 Speak。
Speak 的由来:Joe Ossanna 听说联邦螺丝厂(Federal Screw Works)后屋里有人做出了语音合成器,输入音素就能发音。贝尔实验室有整个部门在做语音合成,但大约一分钟机时才能合成一秒语音;Votrax 则能实时“念”音素串。Joe 说“我们需要一个”,便把它装到机器上,Lee McMahon 很快成了音素串专家,但那仍是苦差事。McIlroy 观察后发现,大量英语词汇(尤其是词典里的大词)可以按语音规则念出来,于是花一夜写了个程序:内置一份“词形片段”音标表,取最长匹配片段来发音,必要时改写一部分再念一部分。第二天 Morris 走到机器前输入“Orlok”,发音完美,说“成功了”——它真的成功了。程序随即常驻上线,任何人都可以走过去输入文字、听机器念出来。主体一夜写成,他又花了六个月打磨,很快投入实际使用。语音部门主管听完后说这是突破;Votrax 的声音不自然但可预测,而对许多任务来说,可预测就够了。McIlroy 特意在词与词之间留了约十毫秒间隔,把语音切成分段——自然语音并不分段,这正是听外语困难的原因之一,因此非英语母语者反而觉得它比真人更容易听懂。唯一没解决的是音节重音,每个音节的轻重都一样。
他还写了 tee 与 tr——用他的话说,这些是“显而易见的东西,一夜就能拼出来”。他更看重拼写检查器 spell:Steve Johnson 发明了那条拼写检查管道,只要词在词典里就工作得很好,但词典必须手工补齐复数与派生形式;McIlroy 做了自动化部分——后缀与前缀处理——把管道变成好用的拼写检查器(大约 1976 年)。他用一条极短的数据处理管道“挑衅”过 Donald Knuth 的庞大程序,原页脚注给出了那条经典命令(tr/sort/uniq 系列)。最终他的词表有三万个词,按平均词长七字符算,对 64K 内存还是太大,于是里面藏着很漂亮的数据压缩;Jon Bentley 还为此写过一期 Programming Pearls 专栏。Bentley 本人也是贝尔实验室的人:他在 Carnegie Mellon 拿到教学奖时,校长致辞说“每当你意识到自己领的是研究薪水而不是教学薪水时,这个奖多少能补偿一下”——Bentley 并不领情,于是来到贝尔实验室,继续用 CACM 专栏“教书”。
贝尔实验室的文化、Plan 9 与 Haskell
McIlroy 说,被贝尔实验室招募的人常讲:“我本来没兴趣来这里——但当我沿走廊走了一圈,看到门上的名字,就改变了主意。”(这话 Thompson 也说过。)贝尔实验室的同事氛围很好:你可以走进任何人的办公室问“谁是这方面的专家”,然后得到帮助;报酬取决于你对公司有多有用,而不是写了多少论文。到了 Dartmouth 后他发现大学并不那么 collegial,尤其那些为终身教职挣扎的助理教授,一分钟都抽不出来分心。
他 1997 年到 Dartmouth。Plan 9 时期他仍在贝尔实验室,但没有参与项目本身。他觉得 Plan 9 没能流行开很可惜——至今仍有一千台左右的机器在跑它——而它的许多想法活了下来:9P 协议、ProcFS,以及“多台计算机与一台计算机没有本质区别”的理念——sockets 和文件还在。Plan 9 还处理了不同机器字节序的问题:数据在机器间移动时自动做必要的字节交换;可执行代码则仍需为不同机器重新编译,但做得非常干净——没有 ifdef,全靠 makefile。至于纯数据如何判断机器类型,他补充:两端都必须运行 Plan 9。
Haskell 方面,McIlroy 说它“是对数学的美丽模仿”。他自称“流处理成瘾者”,而 Haskell 是他所知最好的流处理语言——惰性求值让流与列表完全一致。他用 Haskell 做地图投影:有一类双重周期(doubly periodic)投影,可以把世界地图复制、拼接、平铺整个球面;用高等微积分里的共形映射与椭圆积分可以处理这类投影,他用 Haskell 计算过椭圆积分幂级数展开的系数,还用 Haskell 给自己做圣诞贺卡。Knuth 在《计算机程序设计艺术》第一卷里讲过幂级数运算,其中最复杂的“反演”(求一个幂级数的函数逆)用了半页伪代码,而他用 Haskell 一行就写出了真实可运行的代码。
C 与 Unix 为什么如此持久
访谈者问:为什么 C 与 Unix 的“后代”至今占主导,而 ML、Haskell 一系没有?McIlroy 认为部分原因在于赋值语句——它真的让代码更快。ML 没有赋值语句(“就是不提供”),let 不算数,而且“需要写 let 时你绝不会自豪”;Haskell 完全没有赋值;Lisp 也有一个“不干净的”赋值语句。
至于 Lisp,他打趣说问题在于右括号太多——“这正是管道的可爱之处:它们消灭了右括号。”但管道也消灭了树:管道是一维的线,很多场景需要的是树形组合。他说很遗憾,至今没人找到表达树的漂亮语法;不少 shell 支持树形组合(包括 bash),但没有一种语法令人满意,“我们还没找到”。
一位学生问起他为流式测试设计 DSL 时遇到的语法难题,McIlroy 深表同情:他写过一份提案,从未见天日,因为实在太丑;他反复回头修改,始终没有变好。学生猜测这类组合“本质上是图形化的”;McIlroy 说,结构化编程可以算一个论据——它只覆盖所有可能图的一小部分,但那是极其有用、靠缩进就能写干净的子集;而对“进程连接”,除了线性管道,人们还没找到类似的子集,他也不知道为什么。另一位学生问到编译器与 ABI:从零开始设计系统意味着一切由自己定,McIlroy 承认那是“长设计阶段加短促编码爆发”的模式;他对比 Multics 与 Unix:Multics 有五英尺高的设计文档架,系统却仍跑不起来;Unix 的第一本手册出现在系统诞生两年之后。
尾声
采访因午饭时间而结束,下午还有一系列讲座;McIlroy 留下来听了 elfmaster、netspooky 与 sblip 的演讲。访谈者写道,能与这样一位传奇人物交谈是莫大的荣幸,并感谢 Sergey Bratus 促成了这次 Dartmouth 之行;特别致谢 sblip 负责录音并主导了这场访谈。