Live data from Hacker News

John Carmack on inlined code (2014)

number-none.com

371–380 of 402 posts

Re: John Carmack on inlined code (2014)

#371
post #255

Earlier quoted context omitted.

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…

A lot of sluggishness in modern games isn't even from input latency but from deliberate animations that the character (and even UI) is made to follow.

Re: John Carmack on inlined code (2014)

#372
post #306

Earlier quoted context omitted.

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

> 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... This is stated as if surprising, presumably because we think of a calculator app as a simple thing, but it probably shouldn't be that surprising--surely the calculator app isn't used that often, and so doesn't get much in-the-field testing. Maybe you've occasionally used the calc…

I think this is backwards. A calculator app should be a simple thing. There's nothing undefined or novel about a calculator app. You can buy a much more capable physical calculator from Texas Instruments for less than $100 and I'm pretty sure the CPU in one of those is just an ant with some pen and paper.

You and I only think it's complex because we've become accustomed to everything being complex when it comes to writing software. That's my point. The mathematical operations are not hard (even the "fancy" ones like the trig functions). Formatting a number to be displayed is also not hard (again, those $100 calculators do it just fine). So, why is it so hard to write the world's 100,000th calculator app that the world's highest paid developers can't get it 100% perfect? There's something super wrong with our situation that it's even possible to have a race condition between the graphical effects and the actual math code that causes the calculator to display the wrong results.

If we weren't forced to build a skyscraper with Lego bricks, we might stand a better chance.

Re: John Carmack on inlined code (2014)

#373

His overall solution highlighted in the intro is that he'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. Pure functional programming is the bigger insight here that most programmers will just never understand why there's a benefit there. In fact most programme…

At least for me, it's hard to get that insight, I tried to read articles and watch videos, and none of them gave me say: "oh! now I get it"

Re: John Carmack on inlined code (2014)

#374

His overall solution highlighted in the intro is that he'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. Pure functional programming is the bigger insight here that most programmers will just never understand why there's a benefit there. In fact most programme…

> To most people FP is just a bunch of functional patterns like map, reduce, filter, etc.

For me, these were the gateway drugs to FP, because they weren't available in the languages I was used to, namely C++ and Java. I encountered map and filter in Python in the 1990s, immediately realized a ton of Java and C++ code I wrote would be simpler with them, and dove into Lisp when I found out that's where Python got them. They have nothing to do with pure functional programming, of course; they're just nice idioms that came from functional languages. That led to a long slippery slope of ideas that upgraded my non-FP programming at every step, long before I got into anything that could be described as pure FP.

I don't know if it helps to draw a strict line between "pure" and "impure" FP. I mostly code in Scala, which is an imperative, side-effecting language. Scala gives you exactly the same power as Java to read and mutate global state. However, by design, Scala provides extremely good support for functional idioms, and you can use an effects system (such as Cats Effect or ZIO) to write in a pure FP style. But is it "pure FP" if you can read and mutate global state, and if you have to rely on libraries that are written in Java? Maybe, maybe not, but I don't think trying to answer that question yields much insight.

Re: John Carmack on inlined code (2014)

#375
post #55

I wish languages had the following: let x = block { … return 5 } // x == 5 And the way to mark copypaste, e.g. common foo { asdf(qwerty(i+j)); printf(“%p”, write)); bar(); } …(repeats verbatim 20 times)… … common foo { asdf(qwerty(i+k)); printf(“%d”, (int)write); // cast to int bar(); } … And then you could `mycc diff-common foo` and see: : : common : : common … : : @@…@@ -asdf(qwerty(i+j)); +asdf(qwerty(i+k)); @@…@@…

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…

[deleted]

Re: John Carmack on inlined code (2014)

#376
post #340

Earlier quoted context omitted.

As someone who likes math (math major, applied math grad) and who picked up functional programming relatively early in my career, I don't find this model (fp is just math) to improve my understanding or make it easier to understand why I would want to program like this Talking about state and error handling is helpful because it helps explain why to use the tool, not how the tool was forged (or originally conceived)

This doesn’t help you understand why you should do functional programming. It just helps you understand the nature of what functional programming actually is. Too many people think it’s just immutability, anonymous functions, map, reduce and filter. Understanding why you should do functional programming is orthogonal to understanding what it is. Even if I tell you functional programming is more modular and referentia…

My usual statement on monads is "like any abstraction, it makes sense when you need it"

If you write a lot of go code and think "this error management (!= nil anybody?) is a drag, there has to be a better way! The truth is: go largely looks like how cpp is written at Google, EXCEPT in Google cpp you get to use macros like RETURN_IF_ERROR which handles the ubiquitous StatusOr class.

Is this StatusOr a monad? I'm failing to recall what the monad functions look like internally, but I suspect it's trivial to make it one (I mean, it probably is! And if it's not it would be trivial to make it one)

Do you need to understand monads to see why they're useful here? I don't think so! And so even if you don't know how to build the microwave, you know how to use it.

Re: John Carmack on inlined code (2014)

#377
post #359
post #336

Earlier quoted context omitted.

Ah, but that’s assuming the ‘right way’ path went perfectly and didn’t over-engineer anything. In reality, the ‘right way’ path being advocated for, statistically will also waste a lot of time, and over-engineering waste can and does grow exponentially, while under-engineering frequently only wastes linear and/or small amounts of time, until the problem is better understood. Having witnessed first-hand over-engineeri…

> In reality, the ‘right way’ path being advocated for, statistically will also waste a lot of time, and over-engineering waste can and does grow exponentially, while under-engineering frequently only wastes linear and/or small amounts of time, until the problem is better understood. The “right way” examples I’m thinking of weren’t over-engineering some abstraction that probably wasn’t needed. Picture replacing a lon…

You make a strong case, and you were probably right. It’s always hard to know in a discussion where we don’t have the time and space to share all the details. There’s a pretty big difference between implementing a right way from scratch and using an existing right way that already has test coverage, so that’s an important detail, thank you for the context.

Were there reasons the senior devs objected that you haven’t shared? I have to assume the senior devs had a specific reason or two in each case that wasn’t obviously wrong or idiotic, because it’s quite common for juniors to feel strongly about something in the code without always being able to see the larger team context, or sometimes to discount or disbelieve the objections. I was there too and have similar stories to you, and nowadays sometimes I manage junior devs who think I’m causing them to waste time.

I’m just saying in general it’s healthy to assume and expect imperfect use of time no matter what, and to assume, even when you feel strongly, that the level of abstraction you’re using probably isn’t right. By the Brooks adage, the way your story went down is how some people plan for it to work up front, and if you’d expected to do it twice, then it wouldn’t seem as wasteful, right?

Re: John Carmack on inlined code (2014)

#378

Earlier quoted context omitted.

In C++ you can do: auto f = [&] { ... return barbaz; }(); with the side benefit that you can also make the use of state explicit inside of [] instead of using wildcard capture. Given that it's neither reused nor parametrized, I'm not sure why you see this kind of pattern as a "function by another name", though. Semantically it's more of a namespace if anything.

That literally is a function. I guess the important difference is you can easily confirm by inspection that it is only called once? If that's an important property maybe it would be worth supporting an annotation on normal functions to enforce that. I guess you could easily write a linter for that.

Syntactically it is, but semantically it's really more of an isolated block IMO because not only it's called only once, but that call happens immediately (so no back-and-forth control flow unlike regular functions), and the lambda is not passed anywhere as a value either.

Re: John Carmack on inlined code (2014)

#379

Earlier quoted context omitted.

>For-loops do exist, they just need to not have side effects, No they don't. For loops and loops in general are procedural actions. You are jumping from directive to directive, command to command. Loops are NOT functional at all. loops are an artifact of the computational machine, jumping to different instructions. Functional programs like functions in mathematics DO not contain for loops. > which in practice means t…

Python: def range_mul(n, mul): for i in range(n): yield i*mul x = list(range_mul(10, 20)) range_mul is a pure function, yet it is implemented with a for loop. Once you have first class continuations or the equivalent, the differences between imperative and pure blur (cf. Haskell do-notation, is it imperative?). In any case I think you are missing int_19h point, the it doesn't matter if a function is implemented using…

range_mul is not pure. Don’t believe me? Ask ChatGPT:

“””

No, a Python function that contains the yield keyword is not a pure function.

A pure function is defined as a function where the output is solely determined by its input values, with no observable side effects. This means it should:

• Always return the same result when given the same input. • Have no side effects (like modifying global state, reading from or writing to files, etc.).

Functions containing yield are generators, which maintain internal state between successive calls, making their behavior dependent on the sequence of calls (because they return values incrementally and remember the point where they left off). This internal state makes them impure because they don’t always return the same result when called with the same input—they return successive values upon subsequent calls.

In summary, a function with yield is not pure due to its stateful behavior and non-deterministic output across multiple calls.

“””

>In any case I think you are missing int_19h point, the it doesn't matter if a function is implemented using imperative constructs, if you can't tell from the outside it is still pure. And an FP compiler will convert pure code to imperative anyway.

You’re making a side point here that’s irrelevant to the main point. Sure you can do this, these are techniques you can do to segregate your impure code away from your pure code. But is this the topic of conversation? No.

Additionally your code actually is like a virus. Not only is the example wrong but The impurity can infect other functions that use it such that those functions lose determinism and purity as well.

Which brings me to my main point. Circling back to my parent comment. Most people don’t understand fp and don’t get carmacks insight… and you are an example of such a person for now.

Re: John Carmack on inlined code (2014)

#380
post #358

Earlier quoted context omitted.

>For-loops do exist, they just need to not have side effects, No they don't. For loops and loops in general are procedural actions. You are jumping from directive to directive, command to command. Loops are NOT functional at all. loops are an artifact of the computational machine, jumping to different instructions. Functional programs like functions in mathematics DO not contain for loops. > which in practice means t…

I dunno, I imagine that there's no appreciable difference between: (loop :for i :below 10 :collect i) and: (let loop ((i 0)) (if (= i 10) nil (cons i (loop (1+ i)))))

First off I can’t read that. Please use more common pseudo code for your example if you want me to understand.

Second it looks like there’s a function called for here that does something similar to reduce? That’s a functional thing.

The topic at hand is for loops as in loops that are procedural statements which is what most people recognize as loops. For, while, do while and those things you see in popular languages. Not some obscure construct in lisp.

If your talking about the isomorphism between functional and imperative programming, I already covered that.

Post reply on HN