C++、Python、Rust、Scala构建编译器的差异性究竟有多大?-精品文档资料整理.docx
《C++、Python、Rust、Scala构建编译器的差异性究竟有多大?-精品文档资料整理.docx》由会员分享,可在线阅读,更多相关《C++、Python、Rust、Scala构建编译器的差异性究竟有多大?-精品文档资料整理.docx(30页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、C+、Python、Rust、Scala构建编译器的差异性究竟有多大? C+编程资源合集:海量资源免费下载 C+编程/华为C+编程标准/C+编程练习题大全/编程思想/C+编程实例等资源下载 【编者按】编程语言之争是开发者们热议的永久话题 在不同语言的选择以及设计决定上也都观点不一。那么在面对大型工程时该怎样选择详细实现呢 本文的作者借课程工程之机 比拟了Rust、Haskell、OCaml、C 、Python、Scala 等语言编写的编译器差异 最终发现 这些语言在代码量以及功能实现上简直千差万别 作者 |Tristan Hume 译者 |弯月 责编 | 郭芮 出品 | CSDN ID CSD
2、Nnews 以下为译文 我在滑铁卢大学的最后一个学期选了CS444 编译原理这门课程 课程工程是编写一个编译器 将Java语言的子集编译成x86代码 三人结组 语言自由选择。 这是个难得的时机 我可以在同样的大型工程下比拟不同的实现 而且我的朋友们的程度也跟我很相近 所以我可以借这个时机看看不同的设计以及语言选择。我从这个工程中获得了不少心得 尽管这个比拟并不完美 但比那些仅靠个人观点来比拟编程语言的人要好多了。 我们的编译器是用Rust写成的 首先与另一个使用了Haskell的组进展了比拟。我认为他们的编译器应该更简洁 但实际的代码行数差不多。与另一个使用了OCaml的团队的比拟也得到了同样
3、的结果。然后我与一个使用了C 的团队比拟 结果如我意料的那样 由于有头文件 和缺乏汇总类型以及形式匹配的支持 导致他们的编译器大了30%。下一个是跟我一个朋友的Python实现进展的比拟 他的代码量不到我们的一半 这要归功于元编程以及动态类型。另一个朋友的团队使用了Scala 实现的编译器代码量也小于我们。最让我惊讶的比拟就是与另一个同样使用Rust的团队的比拟 他们的代码量是我们的三倍 因为他们采用了不同的设计决定 这最终导致了同样的功能需要的代码量产生了宏大差异 本文中首先我会来解释一下此次比拟的意义 介绍各个工程的根本情况 然后再解释引发编译器大小差异的局部原因。最后 我会谈一谈从各个比
4、拟中学到的东西。 比拟的意义 你也许会认为 代码行数 我同时比拟了代码行数以及字节数 是个很糟糕的度量 但我认为在这个工程中这种度量可以给出很有用的信息。在我看来 至少代码行数是各个不同的团队在同一个大型工程上工作时最可控的一个变数。 直到我们的工程完成之前 没有任何人 包括我 知道我会统计代码行数 所以没有人在行数度量上做手脚 每个人都尽最大努力来快速、正确地完成工程。每个人 除了后面我会谈到的使用Python的工程之外 都在实现同一个程序 目的只有一个 就是在同样的截止日期之前通过同样的自动化测试套件 所以也不会有某个组试图解决不同的问题 或解决更难的问题的情况。每个组都在这个工程上花了数
5、月的时间 大众都在逐步地添加功能 进而通过已知以及未知的测试。这意味着代码整洁易读 没有任何取巧的地方。 除了要通过的课程测试之外 代码不会被用于任何其他用处 也没人会浏览它 而且由于它只能编译Java语言的一个子集 所以它也没有任何其他用处。除了标准库之外也不允许使用任何库 甚至连辅助解析的库都不允许 假如标准库中没有包含此功能的话 。这意味着也不会出现任何仅有局部团队使用的、强大的编译器库来干扰比拟。 在最终的提交截止日期之后 会运行一次机密的测试 我们看不到该测试 也就是讲 自己编写测试用例并测试代码 可以保证编译器的强健、正确 可以以处理边界情况。 尽管介入的每个人都是学生 但我讨论的
6、这些团队都是我认为非常优秀的程序员。每个人都至少有两年度全职的实习经历 大多数都在高端的科技公司 一些公司甚至还在开发编译器。几乎每个人都有7-13年度的编程经历 都特别热衷在网上浏览课程之外的东西。 自动生成的代码没有统计在内 但生成的语法文件以及代码被统计了。 因此我认为 就各个工程需要花费的精力 和假如是长期工程的话需要花费多少精力去维护而言 代码量是一个很不错的近似统计。我认为 微小的差异也能反映出宏大的问题 比方上面讲过的用Haskell编写的编译器代码量不到C 的一半。 Rust 比拟基准 我以及团队里的另一名成员以前分别写过1万多行的Rust代码 另一个成员在某次编程马拉松工程上
7、写过大约500行Rust。我们的编译器用wc -l统计的结果是6806行 其中包括5900代码行 不包括空行以及注释 wc -c的结果为220kb。 我发现的一个问题是 这几项度量的比例在其他工程中也是相似的 只有一些微小的差异 过会儿我会介绍 。下文中提到代码行数时 我指的都是wc -l的结果 但上述结论说明 代码行数按照哪个规那么进展统计其实是无所谓的 除非十分指出 你可以通过比例进展换算。 我写过另一篇关于设计的文章 :/thume.ca/2019/04/18/writing-a-compiler-in-rust/ 这个设计通过了所有公开以及机密的测试。它还包括几个额外的特性 这些特性我
8、们仅仅是出于兴趣而开发 并没有想着通过测试。这些特性大概占用了400行。我们总共的单元测试以及测试用的代码大约占了500行。 Haskell Haskell团队由我的两个朋友组成 他们每个人大概写过几千行Haskel 还浏览过许多网上的Haskell内容 和许多其他类似的语言 如OCaml以及Lean。他们还有另一个我不太熟悉的团队成员 但似乎是个很厉害的程序员 以前也用过Haskell。 他们编译器的wc -l结果是9750行 357kb 7777 SLOC 源代码行数 。这个团队的度量比例的差异也最大 他们的编译器中行数为1.4倍 SLOC为1.3倍 字节数为1.6倍。他们并没有实现任何额
9、外功能 但通过了所有公开以及机密的测试用例。 需要指出的重要的一点是 只有把测试用例统计在内 对这个团队才公平 因为他们的代码是最正确的 包含了1600行测试用例 并且捕获了好几个团队未能捕获的边界情况 只不过是课程提供的测试用例没有覆盖到这些边界情况而已。所以 假如两者都不统计测试用例的话 他们的代码是8.1k行 我们的是6.3k行 仅是我们的1.3倍。 为了让度量更合理 我还统计了字节数 因为Haskell工程平均每行要更长 而且没有许多只有完毕括号的行 它的单行函数也不会被rustfmt分解成多行。 在与团队里的另一个朋友深化挖掘了代码大小的问题后 我们找到了以下理来历解释代码大小的差异
10、 我们采用了手写的词法分析器以及递归下降分析 recursive descent parsing 他们采用的是NFA到DFA的词法生成器 和一个LR分析器 然后再扫描一遍将解析树转换成AST 抽象语法树 是更方便的代码表示形式 。这需要占用更多代码 占了2677行 比我们的1705行大约多了1k行。 他们使用的是更漂亮的通用AST类型 能转换成不同的类型参数 因为每次解析都会添加更多信息。这需要更多的辅助函数 因此导致了他们的AST代码比我们的实现多了500行我们在解析并添加信息时使用的只是构造字面量 以及可修改的Option _ 字段。 他们大约有400多行代码用于实现更高的抽象程度 进而用
11、纯粹的函数式方式来实当代码生成以及组合 而我们是直接修改字符串。 这些差异再加上测试用例的差异 就导致了代码行数的差异。实际上 我们的文件在中间解析阶段 如常量折叠、作用域解析等 的大小跟他们的非常接近。但仍然产生了字节数上的区别 原因是行的平均长度 我估计原因是他们需要更多的代码 在每次解析时重写整个树 而我们只需要访问并修改即可。 我认为 考虑到Rust以及Haskell的设计决定非常相似 都是表达性的 只有细微的差异 如Rust在需要时可以很方便地修改变量等。另一点有意思的是 我们选择采用递归下降分析器以及手工编写词法分析器给我们带来了回报。固然这有点风险 因为教授并没有推荐这一点 我是
12、自学来的 但我发现它很易于使用 是个正确的决定。 我认为 这个团队可能并没有开发出Haskell的全部潜力。假如他们能更擅长使用Haskell 他们的代码应该行数更少。我相信 像Edward Kmeet之类的人可以使用更少的Haskell代码就能编写出同样的编译器 从这一点上来讲 我朋友的团队并没有使用过多超高级的抽象 而且他们也不允许使用更好的组合库 如lens等。但是 这样做的代价就是理解编译器的难度。团队的成员都是有经历的程序员 他们知道Haskell可以做非常漂亮的事情 但还是决定不这样做 因为他们认为 这样做花费的时间会超过节省的时间 而且会让代码变得难以理解。在我看来这确实是个正确
13、的选择 用“魔法的方式使用Haskell编写编译器 会产生“Haskell写编译器的门槛非常高 假如你不考虑对于不太解析Haskell的人的可维护性的话的结果 而这种结果并不是我们想要的。 另一个有趣的发现是 教授在开场时讲过 学生可以选择任何可以在学校效劳器上运行的语言 但同时针对Haskell提出了警告 讲过去使用Haskell的团队的分数的方差是最高的 因为许多项选择择Haskell的团队都高估了他们的Haskell才能 导致他们的得分比选择其他语言的团队低得多 也有另一局部Haskell团队像我朋友那样做得非常完美。 C 接下来我与另一个在团队中使用了C 的朋友进展了交谈。那个团队中我
14、只认识这一个人 但由于滑铁卢大学中使用C 的课程非常普遍 所以估计团队中的每个人都有C 经历。 他们的工程代码行数为8733 字节数为280kb 这些数字不包括测试代码 但包括大约500行的额外功能。与我们不含测试的代码 也包含500行的额外功能 相比 他们的代码行数为1.4倍。他们通过了100%的公开测试 但仅通过了90%的机密测试 很可能是因为它们没有实现工程要求的数组vtable 这个功能需要大约50-100行代码实现。 我并没有深化挖掘代码差异的原因 我感觉最有可能的解释为 他们使用了LR解析器以及树重写 而没有采用递归下降分析器 C 缺乏汇总类型以及形式匹配这两个非常常用的功能 他们
15、需要重复头文件中所有的函数签名 而Rust不需要这样做。 我们比拟的另一件事是编译时间。在我的笔记本上 我们的编译器的调试版完好编译需要9.7秒 调试版增量编译需要3.5秒。我的朋友并没有给出他们的C 编译器的构建时间 采用并行make 但讲我提供的数字与他们的非常接近 而且讲他们把一些常用的小函数的签名放到了头文件中 以增加编译时间为代价来减少函数签名的重复 也正是由于这个原因 我没有方法比拟单纯的头文件代码行数 。 Python 我的一位朋友是非常优秀的程序员 她选择使用Python独立完成工程。她还比其他团队多实现了好几个额外功能 包括带有存放器分配的SSA立即表示 还有其他优化。另一方
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Python Rust Scala 构建 编译器 差异性 究竟 多大 精品 文档 资料 整理
链接地址:https://www.taowenge.com/p-73273681.html
限制150内