Live data from Hacker News

John Carmack on inlined code (2014)

number-none.com

321–330 of 402 posts

Re: John Carmack on inlined code (2014)

#321
post #261

Earlier quoted context omitted.

> is a way to transmit concepts from one humans head to another (just like writing) That's almost its primary purpose in my opinion... the CPU does not care about Ruby vs Python vs Rust, it's just executing some binary code instructions. The code is so that other people can change and extend what the system is doing over time and share that with others.

I get your point, but often the binary code instructions between those is vastly different.

The fact that we work with the high level languages rather than the binary code, despite all their inefficiencies, speaks to the human aspect being pretty important in the equation.

Re: John Carmack on inlined code (2014)

#322

Earlier quoted context omitted.

Thank you for this. I appreciate that this (classic) article lays bare the essence of FP without the usual pomp and "use Lisp/Scheme/Haskell already" rhetoric. My takeaway is that FP is mostly about using functions w/o side effects (pure), which can be achieved in any programming language provided you're diligent about it.

No functional programming is about programming as if your code is a math equation. In math people never use procedures. They write definitions in math in terms of formulas and expressions. If you can get everything to fit on one line in your programming. Then you are doing functional programming. The lack of side effects, lack of mutation and high modularity are the beneficial outcome of fp, it is not the core of wha…

For-loops do exist, they just need to not have side effects, which in practice means the likes of map/filter/reduce (ideally promoted to a first class language feature like sequence comprehensions).

You could argue that those are still desugared to recursion, but I think at that point it's kinda moot - the construct is still readily recognizable as a loop, and it's most likely also implemented under the hood as an imperative loop with encapsulated local state; not that it matters so long as semantics stay the same.

In general, so long as mutation can be encapsulated in modules that only expose pure functional interfaces, I think it should still count as FP for practical purposes.

Re: John Carmack on inlined code (2014)

#323

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…

I've never seen pure FP...

https://pandoc.org/

Re: John Carmack on inlined code (2014)

#324

Earlier quoted context omitted.

After spending a lot of time writing idiomatic React components in es6, I've found my love of locally declared lambdas to really grow. If I give the lambdas really good names, I find that the main body of my component is very, very readable, even more so than if I'd used a more traditional style liberally sprinkled with comments.

Giving your lambdas names defeats part of their purpose though.

They have two distinct purposes: anonymous functions, and closures. Those often go together, but there are many scenarios where you only care about the latter, and don't actually need the former. Named lambdas (i.e. lambdas assigned to local consts) covers this case if the language doesn't have dedicated syntax for it.

Re: John Carmack on inlined code (2014)

#325
post #85

Earlier quoted context omitted.

Nothing about pure functional programming requires unit testing all of your functions. You can decide to unit test larger or smaller units of code, just as you can in any other paradigm.

In pure functional programming a pure function is unit testable by definition of what a pure function is. I never said it requires functions to be tested. Just that it requires functions to be testable. In other paradigms do not do this. As soon as a module touches IO or state it becomes entangled with that and NOT unit testable. Is it still testable? Possibly. But not as a unit.

How do you unit test a local function that is a closure in pure functional code?

Re: John Carmack on inlined code (2014)

#326
post #240

Earlier quoted context omitted.

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

All that doesn't mean that you have to consider artificial boundaries that you yourself have introduced for convenience when deciding on the proper boundaries for what constitutes a "unit". Not every instance of code reuse makes for a good unit to test.

Re: John Carmack on inlined code (2014)

#327

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

Where is the part, where this is "careful"? This is just how scopes work. I don't see what is special about the inner functions using things in the scope of the outer functions.

Excessive use of external bindings in a closure can make it hard to reason about lifetimes in cases where that matters (e.g. when you find out that a huge object graph is alive solely because some callback somewhere is a lambda that closed over one of the objects in said graph).

Re: John Carmack on inlined code (2014)

#328
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; }

At this point, why wouldn't you just use a nested block?

Re: John Carmack on inlined code (2014)

#329

Earlier quoted context omitted.

In pure functional programming a pure function is unit testable by definition of what a pure function is. I never said it requires functions to be tested. Just that it requires functions to be testable. In other paradigms do not do this. As soon as a module touches IO or state it becomes entangled with that and NOT unit testable. Is it still testable? Possibly. But not as a unit.

How do you unit test a local function that is a closure in pure functional code?

Of course you can't unit test things with restricted scope.

f(x) = x + 2 + 4

How do you unit test x + 2 or (+ 4) even if the operation is pure? You can't. Because it's not callable. It's the same thing with the closure.

The only things that are testable are things on unrestricted scope. AKA global scope. Think about what happens if you have a "closure" on global scope.

If you really want to test it then your "unit tests" which typically live on global scope, need to be moved to local scope. That's just the rules of scope.

There is one special case here. If the parent function returns the local function as a value. But even in this case the parent and local function have to be treated as a unit. The unit test will involve first calling the parent, then calling the local. The parent and child function form a "unit" thanks to shared state and the parent is essentially "moving" the local function into global scope.

Generally best practice is to use combinators if you want to maximize the granularity in which you can modularize your logic. I would even argue that closures stradle the line between pure and impure, so I actually avoid closures whenever possible.

Re: John Carmack on inlined code (2014)

#330

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…

One thing that's nice about functions is that they force the associated block of code to be named, and for state that is specific to the function to be clearly separate from external state (closures aside). It would be good to be able to retain those advantages even in linear code that nevertheless has clear boundaries between different parts of it that would be nice to enforce or at least highlight, but without losing the readability of sequential execution.

To some extent you can have that in languages that let you create a named lambda with explicit captures and immediately invoke it, e.g. in C++:

   int g;

   void doThisAndThat(int a, int b, int c) {

      doThis: auto x = [&a, &b] {
        ...
      }();

      doThat: [&g, &c, &x] {
        ...
      }();
   }
The syntax makes it kind of an eyesore though. Would be nice to have something specifically designed for this purpose.
Post reply on HN