Live data from Hacker News

John Carmack on inlined code (2014)

number-none.com

121–130 of 402 posts

Re: John Carmack on inlined code (2014)

#121

Earlier quoted context omitted.

In C++ it's an idiom to use immediately invoked lambdas: auto x = []{ /*...*/ return 5; }(); There is/was an attempt to introduce a more of a first-class language construct for such immediate "block expressions": https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p28... I'm not convinced that automatic checking of copy-paste errors of such blocks make much sense though. At least I think the false positive rate…

Now if only c++ could guarantee copy elision from lambda returns...

It depends if using C++17 and later versions.

Re: John Carmack on inlined code (2014)

#122

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's slow is all you need 99% of the time.

I find the inlined style can actually improve clarity.

A lot of code written toward the "uncle bob" style where you maximize the number of functions has fantastic local clarity, you can see exactly what the code you are looking at is doing; but atrocious global clarity, where it's nearly impossible to figure out what the system does on a larger scale.

Inlining can help with that, local clarity deteriorates a bit, but global clarity typically improves by reducing the number of indirections. The code does indeed also tend to get faster, as it's much easier to identify and remove redundant code when you have it all in front of you. ... but this also improves the clarity of the code!

You can of course go too far, in either direction, but my sense is that we're often leaning much too far toward short isolated functions now than is optimal.

Re: John Carmack on inlined code (2014)

#123
post #92
post #2

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. Concretely related to the topic, I've often found myself inlining short pieces of one-time code that mad…

[flagged]

Stretch goal: hold three

Re: John Carmack on inlined code (2014)

#124
post #13
post #9

Earlier quoted context omitted.

There’s also the effect that a certain code structure that’s clearer for a senior dev might be less clear for a junior dev and vice versa.

Or rather, senior devs have learned to care more for having clear code rather than (over-)applying principles like DRY, separation of concerns etc., while juniors haven't (yet)...

good devs*, not all senior devs have learned that, sadly. As a junior dev I've worked under the rule of senior devs who were over-applying arbitrary principles, and that wasn't fun. Some absolute nerds have a hard time understanding where their narrow expertise is meant to fit, and they usually don't get better with age.

Re: John Carmack on inlined code (2014)

#125

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. Limiting scope is one of the best tools we have to prevent bugs. It's one reason why we don't just use globals for everything.

You can artificially create scope. I often write code like:

    Foo f = null;
    {
      ... stuff with variables
      f = barbaz;
    }

Re: John Carmack on inlined code (2014)

#126
post #32
post #21

Earlier quoted context omitted.

> Inlining functions also has the benefit of not making it possible to call the function from other places. Congrats, you've got an untestable unit.

Which is usually a positive. Testing tiny subunits usually just makes refactoring and adding new features hard while not improving test quality.

Testing is a tool that sometimes makes your life easier. IME, many (not all) tiny subunits do actually have better tests when examined at that level. You just want to avoid tests which will need to be updated for unrelated changes, and try to avoid writing code which propagates that sort of minutia throughout the codebase:

> while not improving test quality

The big wins from fine-grained testing are

1. Knowing _where_ your program is broken

2. Testing "rare" edge cases

Elaborating on (2), your code probably works well enough on some sort of input or you wouldn't ship it. Tests allow you to cheaply test all four Turkish "i"s and some unicode combining marks, test empty inputs, test what happens when a clock runs backward ever or forward too slowly/quickly, .... You'll hit some of those cases eventually in prod, where pressures are high and debugging/triaging is slow, and integration tests won't usually save you. I'm also a huge fan of testing timing-based logic with pure functions operating on the state being passed in (so it's tested, better than an integration test would accomplish, and you never have to wait for anything godawful like an actual futex or sleep or whatever).

> makes refactoring and adding new features hard

What you're describing is a world where accomplishing a single task (refactoring, adding a new feature) has ripple effects through the rest of the system, or else the tests are examining proxy metrics rather than invariants the tiny subunits should actually adhere to. Testing being hard is a symptom of that design, and squashing the symptom (avoiding tests on tiny subunits) won't fix any of the other problems it causes.

If you're stuck in some codebase with that property and without the ability to change it, by all means, don't test every little setup_redis_for_db_payment_handling_special_case_hulu method. Do, however, test things with sensible, time-invariant names -- data structures, algorithms, anything that if you squint a bit looks kind of like parsing or serialization, .... If you have a finicky loop with a bunch of backoff-related state, pull the backoff into its own code unit and test how it behaves with clocks that run backward or other edge cases. The loop itself (or any other confluence of many disparate coding concepts) probably doesn't need to be unit tested for the reasons you mention, but you usually can and should pull out some of the components into testable units.

Re: John Carmack on inlined code (2014)

#128
post #2

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. Concretely related to the topic, I've often found myself inlining short pieces of one-time code that mad…

> 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?

I think the truth is that we just CAN'T scale that way with the current programming languages/models/paradigms. I can't PROVE that hypothesis, but it's not hard to find examples of big software projects with lots of protocols, conventions, failsafes, QA teams, etc, etc that are either still hugely difficult to contribute to (Linux kernel, web browsers, etc) or still have plenty of bugs (macOS is produced by the richest company on Earth and a few years ago the CALCULATOR app had a bug that made it give the wrong answers...).

I feel like our programming tools are pretty good for programming in the small, but I suspect we're still waiting for a breakthrough for being able to actually make complex software reliably. (And, no, I don't just mean yet another "framework" or another language that's just C with a fancier type system or novel memory management)

Just my navel gazing for the morning.

Re: John Carmack on inlined code (2014)

#130
post #48

Earlier quoted context omitted.

I’ve had the opposite experience before. As a young developer, there were a number of times where I advocated for doing something “the right way” instead of “the good enough way”, was overruled by seniors, and then later I had to fix a bug by doing it “the right way” like I’d wanted to in the first place. Doing it the right way from the start would have saved so much time.

This thread is a great illustration of the reality that there are no hard rules, judgement matters, and we don't always get things right. I'm pretty long-in-the-tooth and feel like I've gone through 3 stages in my career: 1. Junior dev where everything was new, and did "the simplest thing that could possibly work" because I wasn't capable of anything else (I was barely capable of the simple thing). 2. Mid-experience,…

We all go through that cycle. I think the key is to get yourself through that "complex = good" phase as quickly as possible so you do the least damage and don't end up in charge of projects while you're in it. Get your "Second System" (as Brooks[1] put it) out of the way as quick as you can, and move on to the more focused, wise phase.

Don't let yourself fester in phase 2 and become (as Joel put it) an Architecture Astronaut[2].

1: https://en.wikipedia.org/wiki/Second-system_effect

2: https://www.joelonsoftware.com/2001/04/21/dont-let-architect...

Post reply on HN