编程与软件工程number-none.com编辑精选
John Carmack 谈内联代码(2014)
John Carmack on inlined code (2014)
2016 — 2024,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这篇页面转述 John Carmack 关于内联代码的论述,比较把逻辑拆成许多小函数/包装函数与直接写在长函数里的取舍。他强调可读性、调试和性能,并尝试用实际经验(包括 bug 率)评估不同代码风格,而不是只凭教条。评论区进一步讨论了长函数更易顺着读、编译器对内联的优化差异,以及抽象带来的隐藏重复调用。
为什么经久不衰:它把“小函数更清晰”的常识放回可读性、性能和缺陷率的实际权衡中,因此多年后仍值得开发者重读反思。
HN 评论精选
深层小函数嵌套难读,直白长函数易读;Carmack 用 bug 率衡量风格值得称道。
我有幸读过很多别人写的、风格和质量各异的代码。没有什么比从一个小的 helper/wrapper 函数深层嵌套调用到另一个更难读难懂;也没有什么比一个大函数里从上到下直接流过更易读。代码复用、速度、最坏情况速度和引入 bug 的概率还有别的取舍。如果你还没读文章,去读,值得。我喜欢 Carmack 尝试度量哪种风格引入更多 bug!还有谁这么做?真的,我希望看到更多这种做法。
dzdt查看英文原文
I have had the pleasure to work with lots of other people's code of varying styles and quality. Nothing is harder to read and understand than code which is deeply nested calls from one little helper (or wrapper) function to another. Nothing is easier to read and understand than code which just flows straight through from top to bottom of a big function. There are other tradeoffs of code reuse and speed and worst-case-speed and probability of introducing bugs. If you haven't read the article, do, its worth it. I love that Carmack tries to measure which styles introduce more bugs! Who else does that? Seriously, I would love to see more of that.
编译器未必能优化函数封装,内联可能带来显著性能差异。
有趣的是,Casey Muratori 在一次 Handmade Hero 直播中偶然演示了:放进函数里的某些代码,编译器并不总能像内联版本那样优化。视频里,他把一个非常简单的函数内联后,游戏莫名其妙快了一倍。看他深入生成的汇编找出原因很有启发。
lj3查看英文原文
Interestingly, Casey Muratori accidentally demonstrates during one of his Handmade Hero sessions that the compiler won't always be able to optimize certain bits of code that are put in a function as opposed to being inline. In the video, he inlines a very simple function and his game gets twice as fast for no apparent reason. It's instructive to watch him dive into the generated assembly to figure out why. https://www.youtube.com/watch?v=B2BFbs0DJzw
Carmack 的论述是诚实反思而非教条,且他也会犯常见错误。
想象一下和 Carmack 这样的人共事有多棒。当然,最初几次代码评审会很受伤——你很快意识到他比你快且普遍更强——但过一阵你就能放松下来尽量吸收。我喜欢这些邮件里一切都以平静的反思呈现,诚实地记录他自己观点的变化,而不是发号施令。我也觉得挺暖心:他也会犯和我们一样的复制粘贴错误——你有多少次复制一行后两行都留着 x 或 width?Carmack 似乎还真能告诉你他犯过多少次。
bshimmin查看英文原文
Imagine how fantastic it must be working with someone like Carmack. Sure, the first few code reviews would be fairly traumatic - as you quickly realise just how much faster and generally better he is than you - but I think after a little while you could just relax and try to absorb as much as possible. I love how everything in these emails is delivered as a calm series of reflections, chronicling with great honesty his own changing opinions over time - nothing is a diktat. I also found it rather heartening that he makes the same copy/paste mistakes that the rest of us do - how many times have you duplicated a line and put "x" or "width" on both lines..? Seemingly Carmack can actually tell you how many times he's done that!
长函数便于发现重复表达式,局部变量可避免隐藏的重复函数调用。
为长函数辩护的另一个视角是:它能让你发现函数体内重复的表达式/语句。传统智慧建议写一个 is_player_untouched 函数并替换复合表达式,但更直接的重构是提取局部变量,例如 const bool player_untouched = is_player_untouched();,然后在各条件里复用。如果函数体被拆成更多函数以求清晰,你会重复调用 is_player_untouched(),而且这些重复调用藏在调用图深处不易发现。
bluetomcat查看英文原文
Another perspective in defense of long functions is that they enable you to spot common expressions/statements within the body, for example: void long_func(void) { ... if (player.alive && player.health == 100) { .... } ... if (some_other_condition && player.alive && player.health == 100) { } } Conventional wisdom says that you should write a function `is_player_untouched` and substitute the composite expressions with function calls, but the code in question can be refactored in a much more straightforward way: void long_func(void) { ... const bool player_untouched = is_player_untouched(); if (player_untouched) { .... } ... if (some_other_condition && player_untouched) { } } Had the function body been split into more functions for "clarity", you would be doing duplicate calls to `is_player_untouched()` which go unnoticed because they would be buried deep in the call graph.
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选