Live data from Hacker News

John Carmack on inlined code (2014)

number-none.com

281–290 of 402 posts

Re: John Carmack on inlined code (2014)

#281
post #161

I have a coworker that LOVES to make these one or two line single use functions that absolutely drives me nuts. Just from a sheer readability perspective being able to read a routine from top to bottom and understand what everything is doing is invaluable. I have thought about it many times, I wish there was an IDE where you could expand function calls inline.

This can be done in a good way and in bad ways. With most code you will be calling builtin procedures/functions. You also don't look under the hood for those usually. But for the code of your coworker it seems to irritate you. This could mean many things. Just to name a few: (1) The names are not giving a good idea what those functions do. (2) The level of abstraction is not the same inside the calling function, so that you feel the need to check the implementation detail of those small functions. (3) You don't trust the implementation of those smaller functions. (4) The separated out functions could be not worth separating out and being given names, because what the code in them does is clear enough without them being separated out. (n) or some other reason.

The issue does not have to be that those things are split out into separate small functions. The issue might be something else.

Re: John Carmack on inlined code (2014)

#282
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…

I often Bang on about “software is a new form of literacy”. And this I feel is a classic example - software is a form of literacy that not only can be executed by a CPU but also at the same time is a way to transmit concepts from one humans head to another (just like writing) And so asking “will AI generated code help” is like asking “will AI generated blog spam help”? No - companies with GitHub copilot are basically…

Computational thinking is more important than software per se.

Computational thinking is the mathematical thinking.

Re: John Carmack on inlined code (2014)

#283
post #240
post #76

Earlier quoted context omitted.

What do you use unit tests for, other than verifying implementation details? Perhaps we have a difference in definition. To me, a unit test for a function such as "parse_news_email" would explore variations in parameters and states. Because of combinatorial explosion, that often means at least some white-box testing. I'm not going to generate random subjects and senders, and received-froms, I'm going to target based…

> What do you use unit tests for, other than verifying implementation details? 1. Determining when the observable behavior of the program changes. 2. Codifying only the specific behaviors that are known to be relied on by callers. 3. Preventing regressions after bugs are fixed. Failing tests are alarm bells, when do you want them to grab your attention?

Excellent points, violently agree, my question was poorly worded. The purpose of units tests is to verify the contracted API is actually being provided by the implementation details. A clearer question might have been "what are unit tests for if not to exercise the implementation details, verifying they adhere to the API?" Unit tests validate implementation details, integration tests validate APIs.

To me, a good unit test beats the stuffing out of the unit. It's as much a part of the unit as the public functions, so should take full advantage of internal details (keeping test fragility in mind); of course that implies the unit test needs ongoing maintenance just as much as the public functions. If you're passing a small set of inputs and checking the outputs, well that's a smoke test, not a unit test.

To answer your last question, I want the alarm bells to ring whenever the implementation details don't hold up. That's whether the function code changed, a code or state dependency changed, or the testing process itself changed. If at all feasible all the unit tests run every time the the complete suite is run, in full meat-grinder mode. "Complete suite" is hand-wavy; e.g. it might be the suite for a major library, but not the end-to-end application.

Re: John Carmack on inlined code (2014)

#284
post #83

> Inlining functions also has the benefit of not making it possible to call the function from other places. I’ve really gone to town with this in Python. def parse_news_email(…): def parse_link(…): … def parse_subjet(…): … … 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 us…

You can do this in C++, too, but the syntax is a little uglier.

Not that bad?

    int main() {
        int a = -1;
        [&] {
            a = 42;
            printf("I'm an uncallable inline block");
        }();

        printf(" ");

        [&] {
            printf("of code\n");
        }();

        [&] {
            printf("Passing state: %d\n", a);
        }();

        return 0;
    }

Re: John Carmack on inlined code (2014)

#285
post #193

Here are some information theoretic arguments why inlining code is often beneficial: https://benoitessiambre.com/entropy.html In short, it reduces scope of logic. 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 b…

This is why I think it's a mistake that many popular languages, including standard c/c++, do not support nested function definitions. This for me is the happy medium where code can be broken into clear chunks, but cannot be called outside of the intended scope. A good compiler can also detect if the nested function is only called once and inline it.

Code can always be called outside of that scope just by returning function pointers or closures. The point is not to restrict calling that code, but to restrict the ability to refer to that piece of code by name.

As mentioned by others, C++ has lambdas. Even if you don't use lambdas, people used to achieve the same effect by using plenty of private functions inside classes, even though the class might have zero variables and simply holds functions. In even older C code, people are used to making one separate .c file for each public function and then define plenty of static functions within each file.

Re: John Carmack on inlined code (2014)

#286
I’m not even pretending I understood Carmack’s email/mailing list post but if more intelligent/experienced programmers than me care to help me out, what exactly is meant by this he wrote in 2007:

_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._

Thanks,

Re: John Carmack on inlined code (2014)

#287
post #83

Earlier quoted context omitted.

You can do this in C++, too, but the syntax is a little uglier.

Not that bad? int main() { int a = -1; [&] { a = 42; printf("I'm an uncallable inline block"); }(); printf(" "); [&] { printf("of code\n"); }(); [&] { printf("Passing state: %d\n", a); }(); return 0; }

It’s not horrible, a little bit verbose though.

Re: John Carmack on inlined code (2014)

#288

I’m not even pretending I understood Carmack’s email/mailing list post but if more intelligent/experienced programmers than me care to help me out, what exactly is meant by this he wrote in 2007: _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._ Thanks,

This is a heavily simplified version of what I'm suspecting he's trying to portray, key this wouldn't be useful for utility functions like string manipulation but more business logic being used across similar functions:

  def processOrder():
      # Some common processing logic
      print("Processing the order...")
  
  def placeOnlineOrder():
      processOrder()
      print("Sending confirmation email...")
  
  def placeInStoreOrder():
      processOrder()
      print("Printing receipt...")
  
  # Calls from different locations
  placeOnlineOrder()
  placeInStoreOrder()
Could become:

  def processOrder(order_type):
      # Common processing logic
      print("Processing the order...")
  
      if order_type == "online":
          print("Sending confirmation email...")
      elif order_type == "in_store":
          print("Printing receipt...")
  
  # Unified calls with different flags
  processOrder("online")
  processOrder("in_store")

Re: John Carmack on inlined code (2014)

#289

Earlier quoted context omitted.

I'm not sure this is the right way to look at it. I can't find stats right now, but I recall reading top players making frame-perfect moves in games like Smash Bros. Melee and Rocket League.

The mistake with focusing on reaction time is that humans can anticipate actions and can perform complex sequences of actions pretty quickly (we have two hands and 10 fingers). So someone playing one of those "test your reaction time" games might only score like 30ms. But someone playing a musical instrument can still play a 64th note at 120BPM. Imagine playing a drum that took between 0 and 5 extra frames at 60FPS b…

Another example is music (and relatedly, rythm games). With memorized music you have maximal anticipation of actions. The regular rithm only amplifies that anticipation. Musicians can be very consistent at timing (especially rithm section), and very little latency or jitter can throw that off.

Re: John Carmack on inlined code (2014)

#290
post #255

Earlier quoted context omitted.

Why would you even bother running at a game at 120Hz if the user's response to what's being drawn is effectively 24-30 FPS?

You've seen games running at 120Hz and at 60Hz. The difference is obvious, isn't it? The difference between 24Hz and 60Hz is certainly obvious: that's the visual difference between movies and TV sitcoms. I can type about 90 words per minute on QWERTY, which is about 8 keystrokes per second. That means that the average interval between keystrokes is about 120 milliseconds, already significantly less than my 200-millis…

> You've seen games running at 120Hz and at 60Hz. The difference is obvious, isn't it?

Honestly, I have not. I'm not much of a gamer, even though I used to be a game developer.

Certainly the difference between 30Hz and 60Hz is noticeable.

Maybe this is just because I'm old school but if it were me, I would absolutely prioritize low latency over high frame rate. When you played an early console game, the controls felt like they were concretely wired to the character on screen in a way that most games I play today lack. There's a really annoying spongey-ness to how games feel that I attribute largely to latency.

I don't really give a shit about fancy graphics and animation (I prefer 2D games). But I want the controls to feel solid and snappy.

I also make electronic music and it's the same thing there. Making music on a computer is wonderful and powerful in many ways, but it doesn't have the same immediacy as pushing a button on a hardware synth (well, on most hardware synths).

Post reply on HN