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.
John Carmack on inlined code (2014)
321–330 of 402 posts
Re: John Carmack on inlined code (2014)
#322Earlier 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…
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)
#323His 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...
Re: John Carmack on inlined code (2014)
#324Earlier 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.
Re: John Carmack on inlined code (2014)
#325Earlier 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.
Re: John Carmack on inlined code (2014)
#326Earlier 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…
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.
Re: John Carmack on inlined code (2014)
#328Earlier 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; }
Re: John Carmack on inlined code (2014)
#329Earlier 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?
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)
#330Always 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…
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.