TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

John Carmack on inlined code (2014)

556 pointsby bpierre8 months ago

39 comments

mihaic8 months ago
When I first heard the maxim that an intelligent person should be able to hold two opposing thoughts at the same time, I was naive to think it meant weighing them for pros and cons. Over time I realized that it means balancing contradictory actions, and the main purpose of experience is knowing when to apply each.<p>Concretely related to the topic, I&#x27;ve often found myself inlining short pieces of one-time code that made functions more explicit, while at other times I&#x27;ll spend days just breaking up thousand line functions into simpler blocks just to be able to follow what&#x27;s going on. In both cases I was creating inconsistencies that younger developers nitpick -- I know I did.<p>My goal in most cases now is to optimize code for the limits of the human mind (my own in low-effort mode) and like to be able to treat rules as guidelines. The trouble is how can you scale this to millions of developers, and what are those limits of the human mind when more and more AI-generated code will be used?
评论 #41789396 未加载
评论 #41786948 未加载
评论 #41789583 未加载
评论 #41786061 未加载
评论 #41785256 未加载
评论 #41785964 未加载
评论 #41788923 未加载
评论 #41785321 未加载
评论 #41785620 未加载
评论 #41790191 未加载
评论 #41790361 未加载
评论 #41794615 未加载
评论 #41785292 未加载
评论 #41790001 未加载
评论 #41787752 未加载
评论 #41791711 未加载
评论 #41787533 未加载
评论 #41791576 未加载
评论 #41786495 未加载
评论 #41786106 未加载
ninetyninenine7 months ago
His overall solution highlighted in the intro is that he&#x27;s moved on from inlining and now does pure functional programming. Inlining is only relevant for him during IO or state changes which he does as minimally as possible and segregates this from his core logic.<p>Pure functional programming is the bigger insight here that most programmers will just never understand why there&#x27;s a benefit there. In fact most programmers don&#x27;t even completely understand what FP is. To most people FP is just a bunch of functional patterns like map, reduce, filter, etc. They never grasp the true nature of &quot;purity&quot; in functional programming.<p>You see this lack of insight in this thread. Most responders literally ignore the fact that Carmack called his email completely outdated and that he mostly does pure FP now.
评论 #41785930 未加载
评论 #41786084 未加载
评论 #41789247 未加载
评论 #41803544 未加载
评论 #41798570 未加载
评论 #41785780 未加载
评论 #41791336 未加载
评论 #41810938 未加载
评论 #41785858 未加载
评论 #41798519 未加载
评论 #41785545 未加载
VyseofArcadia7 months ago
&gt; That was a cold-sweat moment for me: after all of my harping about latency and responsiveness, I almost shipped a title with a completely unnecessary frame of latency.<p>In this era of 3-5 frame latency being the norm (at least on e.g. the Nintendo Switch), I really appreciate a game developer having anxiety over a single frame.
评论 #41791709 未加载
评论 #41789402 未加载
评论 #41791268 未加载
gorgoiler8 months ago
&gt; Inlining functions also has the benefit of not making it possible to call the function from other places.<p>I’ve really gone to town with this in Python.<p><pre><code> def parse_news_email(…): def parse_link(…): … def parse_subjet(…): … … </code></pre> If you are careful, you can rely on the outer function’s variables being available inside the inner functions as well. Something like a logger or a db connection can be passed in once and then used without having to pass it as an argument all the time:<p><pre><code> # sad def f1(x, db, logger): … def f2(x, db, logger): … def f3(x, db, logger): … def g(xs, db, logger): for x0 in xs: x1 = f1(x0, db, logger) x2 = f2(x1, db, logger) x3 = f3(x2, db, logger) yikes x3 # happy def g(xs, db, logger): def f1(x): … def f2(x): … def f3(x): … for x in xs: yield f3(f2(f1(x))) </code></pre> Carmack commented his inline functions as if they were actual functions. Making actual functions enforces this :)<p>Classes and “constants” can also quite happily live inside a function but those are a bit more jarring to see, and classes usually need to be visible so they can be referred to by the type annotations.
评论 #41785827 未加载
评论 #41785423 未加载
评论 #41785355 未加载
评论 #41785789 未加载
评论 #41785185 未加载
评论 #41786380 未加载
评论 #41785330 未加载
评论 #41785325 未加载
评论 #41786471 未加载
评论 #41785311 未加载
评论 #41786298 未加载
评论 #41786010 未加载
BenoitEssiambre7 months ago
Here are some information theoretic arguments why inlining code is often beneficial:<p><a href="https:&#x2F;&#x2F;benoitessiambre.com&#x2F;entropy.html" rel="nofollow">https:&#x2F;&#x2F;benoitessiambre.com&#x2F;entropy.html</a><p>In short, it reduces scope of logic.<p>The more logic you have broken out to wider scopes, the more things will try to reuse it before it is designed and hardened for broader use cases. When this logic later needs to be updated or refactored, more things will be tied to it and the effects will be more unpredictable and chaotic.<p>Prematurely breaking out code is not unlike using a lot of global variables instead of variables with tighter scopes. It&#x27;s more difficult to track the effects of change.<p>There&#x27;s more to it. Read the link above for the spicy details.
评论 #41788847 未加载
评论 #41791269 未加载
评论 #41843002 未加载
dang7 months ago
Related:<p><i>John Carmack on Inlined Code</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=39008678">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=39008678</a> - Jan 2024 (2 comments)<p><i>John Carmack on Inlined Code (2014)</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=33679163">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=33679163</a> - Nov 2022 (1 comment)<p><i>John Carmack on Inlined Code (2014)</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=25263488">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=25263488</a> - Dec 2020 (169 comments)<p><i>John Carmack on Inlined Code (2014)</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=18959636">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=18959636</a> - Jan 2019 (105 comments)<p><i>John Carmack on Inlined Code (2014)</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14333115">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14333115</a> - May 2017 (2 comments)<p><i>John Carmack on Inlined Code (2014)</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=12120752">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=12120752</a> - July 2016 (199 comments)<p><i>John Carmack on Inlined Code</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=8374345">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=8374345</a> - Sept 2014 (260 comments)
评论 #41790772 未加载
dehrmann7 months ago
Always read older stuff from Carmack remembering the context. He made a name for himself getting 3D games to run on slow hardware. The standard advice of write for clarity first, make sure algorithms have reasonable runtimes, and look at profiler data if it&#x27;s slow is all you need 99% of the time.
评论 #41786778 未加载
评论 #41785455 未加载
评论 #41785433 未加载
low_tech_love7 months ago
Interesting: this is a 2014 post from Jonathan Blow reproducing a 2014 comment by John Carmack reproducing a 2007 e-mail by the same Carmack reproducing a 2006 conversation (I assume also via e-mail) he had with a Henry Spencer reproducing something else the same Spencer read a while ago and was trying to remember (possibly inaccurately?).<p>I wonder what is the actual original source (from Saab, maybe?), and if this indeed holds true?
评论 #41792323 未加载
donatj7 months ago
I have a coworker that LOVES to make these one or two line single use functions that absolutely drives me nuts.<p>Just from a sheer readability perspective being able to read a routine from top to bottom and understand what everything is doing is invaluable.<p>I have thought about it many times, I wish there was an IDE where you could expand function calls inline.
评论 #41788172 未加载
评论 #41791712 未加载
评论 #41789131 未加载
adamrezich7 months ago
I find that when initially exploring a problem space, it&#x27;s useful to consider functions as “verbs” to help me think through the solution, and that feels useful in helping me figure out a solution to my problem—I&#x27;ve isolated some_operation() into its own function, and it&#x27;s easy to see at a glance whether or not some_operation() does the specific thing its name claims to do (and if so, how well).<p>But then after things have solidified somewhat, it&#x27;s good practice to go back through your code and determine whether those “verbs” ended up being used more than once. Quite often, something that I thought would be repeated enough to justify being its own function, is actually only invoked in one specific place—so I go back and inline these functions as needed.<p>The less my code looks like a byzantine tangle of function invocations, and the more my code reads like a straightforward list of statements to execute in order, the better it makes me feel, because I know that I&#x27;m not unnecessarily hiding complexity, and I can get a better, more concrete feel for what my program&#x27;s execution looks like.
Cthulhu_7 months ago
I feel like this style is also encouraged in Go and &#x2F; or the clean&#x2F;onion architecture &#x2F; DDD, to a point, where the core business logic can and should be a string of &quot;do this, then do that, then do that&quot; code. In my own experience I&#x27;ve only had a few opportunities to do so (most of my work is front-end which is a different thing entirely), the one was application initialisation (Create the logger, then connect to the database, then if needed initialize &#x2F; migrate it, then if needed load test data. Then create the core domain services that uses the database connection. Then create the HTTP handlers that interface with the domain services. Then start the HTTP server. Then listen for an end process command and shut down gracefully), the other was pure business logic (read the database, transform, write to file, but &quot;database&quot; and &quot;file&quot; were abstract concepts that could be swapped out easily). You don&#x27;t really get that in front-end programming though, it&#x27;s all event driven etc.
评论 #41785565 未加载
torginus7 months ago
&quot;Typically I am there to rail against the people that talk about using threads and an RTOS for such things, when a simple polled loop that looks like a primitive video game is much more clear and effective. &quot;<p>Yess, I finally feel vindicated. I&#x27;ve been having this argument with embedded people since forever. I was of the opinion that if million line big boy PC apps can make do with just one thread, having fifteen threads and synchronizing between them using mutexes and condition variables on a microcontroller with 64kb RAM is just bonkers.<p>For some reason, the statement that a while(true) loop + ISRs + DMA can do everything an RTOS like FreeRTOS can do, can rile up embedded folks to no end.
otikik7 months ago
&gt; I have gotten much more bullish about pure functional programming, even in C&#x2F;C++ where reasonable: (link)<p>The link is no longer valid, I believe this is the article in question:<p><a href="https:&#x2F;&#x2F;www.gamedeveloper.com&#x2F;programming&#x2F;in-depth-functional-programming-in-c-" rel="nofollow">https:&#x2F;&#x2F;www.gamedeveloper.com&#x2F;programming&#x2F;in-depth-functiona...</a>
评论 #41785617 未加载
djha-skin7 months ago
This largely concurs with clean architecture[1], especially considering his foreword containing hindsight.<p>Clean architecture can be summarized thusly:<p>1. Bubble up mutation and I&#x2F;O code.<p>2. Push business logic down.<p>This is how it&#x27;s stated in [1]:<p>&gt; The concentric circles represent different areas of software. In general, the further in you go, the higher level the software becomes. The outer circles are mechanisms. The inner circles are policies.<p>Inlining as a practice is in service of #1, while factoring logic into pure functions addresses #2, noted in the foreword:<p>&gt; The real enemy addressed by inlining is unexpected dependency and mutation of state, which functional programming solves more directly and completely. However, if you are going to make a lot of state changes, having them all happen inline does have advantages; you should be made constantly aware of the full horror of what you are doing. When it gets to be too much to take, figure out how to factor blocks out into pure functions (and don.t let them slide back into impurity!).<p>1: <a href="https:&#x2F;&#x2F;blog.cleancoder.com&#x2F;uncle-bob&#x2F;2012&#x2F;08&#x2F;13&#x2F;the-clean-architecture.html" rel="nofollow">https:&#x2F;&#x2F;blog.cleancoder.com&#x2F;uncle-bob&#x2F;2012&#x2F;08&#x2F;13&#x2F;the-clean-a...</a>
physicsguy7 months ago
I think when developing something from scratch, it&#x27;s actually not a terrible strategy to do this and pick out boundaries when they become clearer. Creating interfaces that make sense is an art, not a science.
nuancebydefault7 months ago
&gt; The function that is least likely to cause a problem is one that doesn’t exist, which is the benefit of inlining it.<p>I think that summarizes the case pro inlining.
exodust7 months ago
For some reason this quote by Carmack stands out for me:<p>&gt; <i>&quot;it is often better to go ahead and do an operation, then choose to inhibit or ignore some or all of the results, than try to conditionally perform the operation.&quot;</i><p>I&#x27;m not the audience for this topic, I do javascript from a designer-dev perspective. But I get in the weeds sometimes, maxing out my abilities and bogged down by conditional logic. I like his quote it feels liberating... &quot;just send it all for processing and cherry-pick the results&quot;. Lightbulb moment.
评论 #41787714 未加载
wruza7 months ago
I wish languages had the following:<p><pre><code> let x = block { … return 5 } &#x2F;&#x2F; x == 5 </code></pre> And the way to mark copypaste, e.g.<p><pre><code> common foo { asdf(qwerty(i+j)); printf(“%p”, write)); bar(); } …(repeats verbatim 20 times)… … common foo { asdf(qwerty(i+k)); printf(“%d”, (int)write); &#x2F;&#x2F; cast to int bar(); } … </code></pre> And then you could `mycc diff-common foo` and see:<p><pre><code> &lt;file&gt;:&lt;line&gt;: common &lt;file&gt;:&lt;line&gt;: common … &lt;file&gt;:&lt;line&gt;: @@…@@ -asdf(qwerty(i+j)); +asdf(qwerty(i+k)); @@…@@ -printf(“%p”, write)); +printf(“%d”, (int)write); &#x2F;&#x2F; cast to int </code></pre> With this you can track named common blocks (allows using surrounding context like i,j,k). Without them being functions and subject for functional entanglement $subj discusses. Most common code gets found out and divergences get bold. IDE support for immediate highlighting, snippeting and auto-common-ing similar code would be very nice.<p>Multi-patching common parts with easily reviewing the results would also be great. Because the bugs from calling a common function arise from the fact that you modify it and it suddenly works differently for some context. Well, you can comment a common block as fragile and then ignore it while patching:<p><pre><code> common foo { &#x2F;&#x2F; @const: modified and fragile! … } </code></pre> You still see differences but it doesn’t add in a multi-patch dialog.<p>Not expecting it to appear anywhere though, features like that are never considered. Maybe someone interested can feature it in circles? (without my name associated)
评论 #41785849 未加载
评论 #41915538 未加载
评论 #41792772 未加载
评论 #41785870 未加载
kazinator7 months ago
In my opinion, there is value in functions that have only one caller: it&#x27;s called functional decomposition. The right granularity of functional decomposition can make the logic easier to understand.<p>To prevent unintended uses of a helper function in C, you can make it static. Then at least nothing from outside of that translation unit can call it.
rcv7 months ago
&gt; The fly-by-wire flight software for the Saab Gripen (a lightweight fighter) went a step further...<p>I would love to hear some war stories about the development of flight software. A lot of it is surely classified, but I&#x27;m fascinated by how those systems are put together.
评论 #41802347 未加载
IshKebab7 months ago
I think the major problem with this is scope. Now a variable declared at the top of your function is in scope for the entire function.<p>Limiting scope is one of the best tools we have to prevent bugs. It&#x27;s one reason why we don&#x27;t just use globals for everything.
评论 #41786852 未加载
endlessmike897 months ago
Link to the Wayback Machine cache&#x2F;mirror, in case you&#x27;re also experiencing a &quot;Bad Gateway&#x2F;Connection refused&quot; error<p><a href="https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20241009062005&#x2F;http:&#x2F;&#x2F;number-none.com&#x2F;blow&#x2F;blog&#x2F;programming&#x2F;2014&#x2F;09&#x2F;26&#x2F;carmack-on-inlined-code.html" rel="nofollow">https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20241009062005&#x2F;http:&#x2F;&#x2F;number-non...</a>
roeles7 months ago
&gt; No bug has ever been found in the “released for flight” versions of that code.<p>I thought that at least his crash was a result of bad constants in flight software: <a href="https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=SWZLmVqNaQc" rel="nofollow">https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=SWZLmVqNaQc</a><p>The first comment appears to agree with me.
lencastre7 months ago
I’m not even pretending I understood Carmack’s email&#x2F;mailing list post but if more intelligent&#x2F;experienced programmers than me care to help me out, what exactly is meant by this he wrote in 2007:<p>_If a function is called from multiple places, see if it is possible to arrange for the work to be done in a single place, perhaps with flags, and inline that._<p>Thanks,
评论 #41791866 未加载
easeout7 months ago
Come to think of it, execute-and-inhibit style as described here is exactly what&#x27;s going on when in continuous deployment you run your same pipeline many times a day with small changes, and gate new development behind feature flags. We&#x27;re familiar with the confidence derived from frequently repeating the whole job.
sylware7 months ago
I have been super picky about what JC says since he moved the ID engine from plain and simple C99 to c++.
shortrounddev27 months ago
Can someone explain what inlined means here? It was my assumption that the compiler will automatically inline functions and you don&#x27;t need to do it explicitly. Unless it means something else in this context
评论 #41788011 未加载
评论 #41803728 未加载
rossant8 months ago
(2014)
评论 #41785215 未加载
评论 #41785291 未加载
fabiensanglard7 months ago
How does a program work when its disallow &quot;backward branches&quot;. Same thing with &quot;subroutine calls&quot; how do you structure a program without them?
评论 #41791157 未加载
评论 #41790842 未加载
评论 #41793324 未加载
randomtoast7 months ago
My browser says &quot;The connection to number-none.com is not secure&quot;. Guess it is only a matter of time until HTTPS becomes mandatory.
ydnaclementine7 months ago
&gt; do always, then inhibit or ignore strategy<p>can anyone expound on this? I&#x27;m not sure what he&#x27;s exactly referring to here
Ono-Sendai7 months ago
There is actually a major problem with long functions - they take a long time to compile, due to superlinear complexity in computation time as a function of function length. In other words breaking up a large function into smaller function can greatly reduce compile times.
评论 #41785819 未加载
评论 #41786680 未加载
gdiamos8 months ago
How much of this is specific to control loops that execute at 60hz?
评论 #41785253 未加载
评论 #41785316 未加载
评论 #41785397 未加载
评论 #41786091 未加载
jjallen7 months ago
One benefit that I can think of for inlined code is the ability to &quot;step&quot; through each time step&#x2F;tick&#x2F;whatever and debug the state at each step of the way.<p>And one drawback I can think of is that when there are more than something like ten variables finding a particular variable&#x27;s value in an IDE debugger gets pretty difficult. It would be at this point that I would use &quot;watches&quot;, at least in the case of Jetbrains&#x27;s IDEs.<p>But then yeah you can also just log each step in a custom way verifying the key values are correct which is what I am doing as we speak.
rickreynoldssf7 months ago
The clean code people are losing their collective minds reading that. lol
评论 #41788638 未加载
oglop7 months ago
Oh good, a FP post. I love watching people argue over nothing.<p>Here’s the actual rule, do what works and ships. Don’t posture. Don’t lament. Don’t idealize. Just solve the fucking problem with the tool and method that fits and move on.<p>And do not try to use this comment threat to understand FP. Too many cooks, and most of the are condescending douchebags. Go look at Wikipedia or talk with an AI about it. Don’t ask this place, it’s all just lectures and nitpicks.
评论 #41797008 未加载
评论 #41789768 未加载
评论 #41789922 未加载
mellosouls7 months ago
(2014)<p>Ten years ago - a long time in coding.
评论 #41787339 未加载
Myrmornis7 months ago
This is the real religious war among programmers -- it&#x27;s a genuinely consequential question: someone who favors abstraction and modularity is going to absolutely hate working in a codebase with pervasively inlined code.<p>It&#x27;s clear that Carmack&#x27;s article is addressing a particular sort of C++ codebase that might be familiar to game developers, but isn&#x27;t familiar to a lot of us here who work on web applications and backend distributed systems. His &quot;functions&quot; aren&#x27;t really what we think of as functions: they&#x27;re clearly mutating huge amounts of global state. They sound more like highly undisciplined methods on large namespaces. You can see that from the following quotes:<p>&gt; There might be a FullUpdate() function that calls PartialUpdateA(), and PartialUpdateB(), but in some particular case you may realize (or think) that you only need to do PartialUpdateB(), and you are being efficient by avoiding the other work. Lots and lots of bugs stem from this. Most bugs are a result of the execution state not being exactly what you think it is.<p>&gt; if a function only references a piece or two of global state, it is probably wise to consider passing it in as a variable.<p>In the world of many people here, i.e. away from Carmack&#x27;s C++ game dev codebases of the 2000s with huge amounts of global mutable state, the standard common sense still applies: we invented structured programming with functions for profoundly important reasons: modularity and abstraction. Those reasons haven&#x27;t gone away; use functions.<p>- In a large codebase you do not need or want to read the full tree of implementation in one go. Use functions: they have return types; you know what they do. A substantial piece of implementation should be written as a sequence of calls to subfunctions with very carefully chosen names that serve as documentation in themselves.<p>- Make your functions as pure as possible subject to performance considerations etc.<p>- This brings a huge advantage to helper functions over inlining: it is now easy to see which variables in the top-level function are being mutated.<p>- The implementation is much harder to understand in a single function with 10 mutable variables, than in two functions with 5 mutable variables. I think ultimately that&#x27;s just a fact of combinatorics; not something we can hold opinions about.<p>- But sure, if the 10 mutable variables cannot be decomposed into two independent modules then don&#x27;t create spurious functions.<p>- A separate function is testable; a block inside a function is not. It wasn&#x27;t really clear that the sort of test suites that many of us here work with were part of Carmack&#x27;s codebases at all!<p>- It is absolutely fine to use a function if it improves modularity &#x2F; readability even if it only called once.
atulvi7 months ago
who read this in John Carmack&#x27;s voice?