Live data from Hacker News

John Carmack on inlined code (2014)

number-none.com

311–320 of 402 posts

Re: John Carmack on inlined code (2014)

#314

Earlier quoted context omitted.

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 A…

Heh, I've read [2] before but another reading just now had this passage stand out: > Another common thing Architecture Astronauts like to do is invent some new architecture and claim it solves something. Java, XML, Soap, XmlRpc, Hailstorm, .NET, Jini, oh lord I can’t keep up. And that’s just in the last 12 months! > I’m not saying there’s anything wrong with these architectures… by no means. They are quite good archi…

Both React and Vue are older than 10 years old at this point. Both are older than jQuery was when they were released, and both have a better backward compatibility story. The only two real competitors not that far behind. It's about time for this crappy frontend meme to die.

Even SOAP didn't really live that long before it started getting abandoned en masse for REST.

As someone who was there in the "last 12 months" Joel mentions, what happened in enterprise is like a different planet altogether. Some of this technology had a completely different level of complexity that to this day I am not able to grasp, and the hype was totally unwarranted, unlike actual useful tech like React and Vue (or, out of that list, Java and .NET).

Re: John Carmack on inlined code (2014)

#315

How does a program work when its disallow "backward branches". Same thing with "subroutine calls" how do you structure a program without them?

It allows one backward branch. Think of it like hand-rolling your OS scheduler for processes/threads. You also have to track your "program counter" yourself. As a silly example:

  typedef enum state {EVEN, ODD} state_t;
  state_t task1 = EVEN;
  state_t task2 = EVEN;
  while (1) {
    switch(task1) {
    case EVEN:
        // do even things
        task1 = ODD;
        break;
    case ODD:
        // do odd things
        task1 = EVEN;
        break;
    default:
        fprintf(stderr, "WTF?\n");
        exit(1);
    }
    switch(task2) {
    case EVEN:
        // do even things
        task2 = ODD;
        break;
    case ODD:
        // do odd things
        task2 = EVEN;
        break;
    default:
        fprintf(stderr, "WTF?\n");
        exit(1);
    }
  }
For every "process" you've unrolled like this, you have to place it into its own switch/case or call out to a function which has similar logic (when subroutines aren't disallowed). If the process is short enough you let it execute all the way through, bigger processes would need to be broken apart like above to avoid consuming an entire cycle's time (especially important in real-time systems).

Re: John Carmack on inlined code (2014)

#316
post #144

Earlier quoted context omitted.

I think the only way this gets better is with software development tools that make it impossible to create invalid states. In the physical world, when we build something complex like a car engine, a microprocessor, or bookcase, the laws of physics guide us and help prevent invalid states. Not all of them -- an upside down bookcase still works -- but a lot of them. Of course, part of the problem is that when we build…

John Backus's Turing Award lecture meditated on this idea, and concluded that the best way to do this at scale is to simply minimize the creation of states in the first place, and be careful and thoughtful about where and how we create the states that can't be avoided. I would argue that that's actually a better guide to how we manage complexity in the physical world. Mechanical engineers generally like to minimize t…

I'd say that the extra moving parts are there in most cases not because someone wanted to "feel smart" (not that it doesn't happen), but to make the pre-existing moving parts do something that they weren't originally supposed to do, because nobody understands how those pre-existing parts work well enough to re-engineer them properly on the schedule that they are given. We are an industry that builds bridges out of matchsticks, duck tape, and glue, and many of our processes are basically about how to make the result of that "good enough".

Re: John Carmack on inlined code (2014)

#317
post #82
post #8

Earlier quoted context omitted.

None. > 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…

I have worked with many developers and I have seen them follow two distinct paths when encountering complex code. There's one camp that wants to use abstractions and names, and there's another (in my experience, smaller) camp which prefers to have as few abstractions as possible, and "every gritty detail visible". I think both strategies have advantages and disadvantages. The group that likes abstractions can "ignore…

Some might consider me part of the "second group", but I'm perfectly fine with abstractions and I create them all the time.

I do however have a problem with indirections that don't really abstract anything and only exist for aesthetical reasons.

Not every function/method is an "abstraction". Having too many one-line methods is as bad as pretending that functions with 2k/3k lines are appropriate in all cases.

Re: John Carmack on inlined code (2014)

#318
post #305

Earlier quoted context omitted.

It's more case by case for me. A magic number should get a named constant on its first use. That's an abstraction.

C++ programmers decided against NULL, and for well over a decade, recommended using a plain 0. It was only recently that they came up with a new name: nullptr. Sigh.

That had to do with the way NULL was defined, and the implications of that. The implication carried over from C was that NULL would always be null pointer as opposed to 0, but in practice the standard defined it simply as 0 - because C-style (void*)0 wasn't compatible with all pointer types anymore - so stuff like:

   void foo(void*);

   void foo(int); 

   foo(NULL);
would resolve to foo(int), which is very much contrary to expectations for a null pointer; and worse yet, the wrong call happens silently. With foo(0) that behavior is clearer, so that was the justification to prefer it.

On the other hand, if you accept the fact that NULL is really just an alias for 0 and not specifically a null pointer, then it has no semantic meaning as a named constant (you're literally just spelling the numeric value with words instead of digits!), and then it's about as useful as #define ONE 1

And at the same time, that was the only definition of NULL that was backwards compatible with C, so they couldn't just redefine it. It had to be a new thing like nullptr.

It is very unfortunate that nullptr didn't ship in C++98, but then again that was hardly the biggest wart in the language at the time...

Re: John Carmack on inlined code (2014)

#319

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.

And before that, 2D games (side-scrolling platformers were not a thing on PC hardware until Carmack did it, iirc). I think his main thing is balancing clarity - what happens when and in what order - with maintainability. Compare this with enterprise software, which is orders of magnitude more complex than video games in terms of business logic (the complexity in video games is in performance optimization), but whose…

> And before that, 2D games (side-scrolling platformers were not a thing on PC hardware until Carmack did it, iirc). I think his main thing is balancing clarity - what happens when and in what order - with maintainability.

Smooth side-scrollers did exist on the PC before Keen (An early one would be the PC port of Defender). Moon Patrol even had jumping in the early '80s.

Furthermore other contemporaries of Carmack were making full-fledged side-scrolling platformers in ways different from how Keen did it (there were many platformers released in 1990). They all involved various limitations on level design (as did what Keen used), but I don't believe any of them allowed both X and Y scrolling like the Keen games did.

Re: John Carmack on inlined code (2014)

#320
post #170
post #13

Earlier quoted context omitted.

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

I find that it’s typically the other way around as things like DRY, SOLID and most things “clean code” are hopeless anti-patterns peddled by people like Uncle Bob who haven’t actually worked in software development since Fortran was the most popular language. Not that a lot of these things are bad as a principle. They come with a lot of “okish” ideas, but if you follow them religiously you’re going to write really ba…

The problem with repeating code in multiple places is that when you find a bug in said code, it won't actually be fixed in all the places where it needs to be fixed. For larger projects especially, it is usually a worthwhile tradeoff versus having to peel off some extra abstraction layers when reading the code.

The problems usually start when people take this as an opportunity to go nuts on generalizing the abstraction right away - that is, instead of refactoring the common piece of code into a simple function, it becomes a generic class hierarchy to cover all conceivable future cases (but, somehow, rarely the actual future use case, should one arise in practice).

Most of this is just cargo cult thinking. OOP is a valid tool on the belt, and it is genuinely good at modelling certain things - but one needs to understand why it is useful there to know when to reach for it and when to leave it alone. That is rarely taught well (if at all), though, and even if it is, it can be hard to grok without hands-on experience.

Post reply on HN