Fors = data flow / compute kernel
it makes sense to keep control flow and data flow separated for greater efficiency, so that you independently evolve either of flows while still maintaining consistent logic
101–110 of 209 posts
Fors = data flow / compute kernel
it makes sense to keep control flow and data flow separated for greater efficiency, so that you independently evolve either of flows while still maintaining consistent logic
Earlier quoted context omitted.
You can't shove every single assumption into the type system...
[flagged]
> with admirable tunnel vision, bullheadedness and mission for maximally general algebraic and arbitrary constraint type systems.
I believe they're called keyhole optimizations, greedy search, and "the customer is always right..."But I like to help the compiler with this kind of optimization, by just doing it in the code. Let the compiler focus on optimizations that I can't.
My weird mental model: You have a tree of possible states/program flow. Conditions prune the tree. Prune the tree as early as possible so that you have to do work on fewer branches. Don’t meticulously evaluate and potentially prune every single branch, only to find you have to prune the whole limb anyways. Or even weirder: conditionals are about figuring out what work doesn’t need to be done. Loops are the “work.” Ul…
I strongly disagree with this ifs take. I want to validate data where it is used. I do not trust the caller (myself) to go read some comment about the assumptions on input data a function expects. I also don't want to duplicate that check in every caller.
You'll end up duplicating the condition, but that seems like a reasonable price to pay for correct and performant software.
Sometimes I like to put the conditional logic in the callee because it prevents the caller from doing things in the wrong order by accident. Like for example, if you want to make an idempotent operation, you might first check if the thing has been done already and if not, then do it. If you push that conditional out to the caller, now every caller of your function has to individually make sure they call it in the rig…
You’ve kind of answered your own question here. > If you push that conditional out to the caller, now every caller of your function has to individually make sure they call it in the right way to get a guarantee of idempotency In this situation your function is no longer idempotent, so you obviously can’t provide the guarantee. But quite frankly, if you’re having to resort to making individual functions implement stat…
Earlier quoted context omitted.
The way to solve this is to split decisions from execution and that’s a notion I got from our old pal Bertrand Meyer. if (weShouldDoThis()) { doThis(); } It complements or is part of functional core imperative shell. All those checks being separate makes them easy to test, and if you care about complexity you can break out a function per clause in the check.
Functions should decide or act, not both.
Earlier quoted context omitted.
This is why we invented type systems. No need to examine call chains, just examine input types. The types will not only tell you what assumptions you can make, but the compiler will even tell you if you make an invalid assumption!
You can't shove every single assumption into the type system...
With AVX-512 for example, trivial branching can be replaced with branchless code using the vector mask registers k0-k7, so an if inside a for is better than the for inside the if, which may have to iterate over a sequence of values twice.
To give a basic example, consider a loop like:
for (int i = 0; i
We can convert this to one which operates on 16 ints per loop iteration, with the loop body containing no branches, where each int is only read and written to memory once (assuming length % 16 == 0). __mmask16 consequents;
__mmask16 alternatives;
__mm512i results;
__mm512i ones = _mm512_set1_epi32(1);
__mm512i twos = _mm512_set1_epi32(2);
for (int i = 0; i
Ideally, the compiler will auto-vectorize the first example and produce something equivalent to the second in the compiled object.