Live data from Hacker News

Push Ifs Up and Fors Down

matklad.github.io

111–120 of 209 posts

Re: Push Ifs Up and Fors Down

#111
I just wrote some code with this "dilemma" a minute ago. But I was worried the callers forget to include the "if" so I put it inside the method. Instead, I renamed the method from "doSomething" to "maybeDoSomething".

Re: Push Ifs Up and Fors Down

#112

Earlier quoted context omitted.

Functions should decide or act, not both.

But if that’s all you have, then how does your system do anything ? You ultimately need to be able to decide and then act based in that decision somewhere..

One possibility is a file.py that is called by your framework. The interface could be something like

  def doth_match(*args):
    return True  # the predicate

  def doeth_thou(*args):
    # processing things
    return {}  # status object for example
The framework loops and checks the first function; if true, then execute the second function. And then break or continue for other rule files (or objects).

There could be multiple files rule1.py, rule2.py, etc that check and do different things.

Re: Push Ifs Up and Fors Down

#113
> If there’s an if condition inside a function, consider if it could be moved to the caller instead

This idle conjecture is too rife with counterexamples.

- If the function is called from 37 places, should they all repeat the if statement?

- What if the function is getaddrinfo, or EnterCriticalSection; do we push an if out to the users of the API?

I think that we can only think about this transformation for internal functions which are called from at most two places, and only if the decision is out of their scope of concern.

Another idea is to make the function perform only the if statement, which calls two other helper functions.

If the caller needs to write a loop where the decision is to be hoisted out of the loop, the caller can use the lower-level "decoded-condition helpers". Callers which would only have a single if, not in or around a loop, can use the convenience function which hides the if. But we have to keep in mind that we are doing this for optimization. Optimization often conflicts with good program organization! Maybe it is not good design for the caller to know about the condition; we only opened it up so that we could hoist the condition outside of the caller's loop.

These dilemmas show up in OOP, where the "if" decision that is in the callee is the method dispatch: selecting which method is called.

Techniques to get method dispatch out of loops can also go against the grain of the design. There are some patterns for it.

E.g. wouldn't want to fill a canvas object with a raster image by looping over the image and calling canvas.putpixel(x, y, color). We'd have some method for blitting an image into a canvas (or a rectangular region thereof).

Re: Push Ifs Up and Fors Down

#114
post #105

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…

Can I float an adjacent model? Classes are nouns, functions are verbs.

I remember being taught that in CS101 and still use it today 15 years later. It's a good and simple and easy to follow pattern

Re: Push Ifs Up and Fors Down

#115
post #16

Push everything down for better code readability printInvoice(invoice, options) // is much better than if(printerReady){ if(printerHasInk){ if(printerHasPaper){ if(invoiceFormatIsPortrait){ : The same can be said of loops printInvoices(invoices) // much better than for(invoice of invoices){ printInvoice(invoice) } At the end, while code readability is extremely important, encapsulation is much more important, so mix…

> Push everything down for better code readability

> demonstrates arrow anti-pattern

Ewwww gross. No. Do this instead:

if(!printerReady){ return; } if(!printerHasInk){ return; } if(!printerHasPaper){ return; } if(!invoiceFormatIsPortrait){ return; }

Way more readable than an expanding arrow.

> printInvoices(invoices) // much better than

But yes, put the loop into its own function with all of the other assumptions already taken care of? This is good.

Re: Push Ifs Up and Fors Down

#116

In some cases you want to do the opposite - to utilize SIMD. 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 pe…

My first thought was conditional branches inside the for loop based on the element as well. By any chance, do you know how hard it is for compilers to auto-vectorize something like this? I am generally not sure where the boundary is.

Re: Push Ifs Up and Fors Down

#117

In some cases you want to do the opposite - to utilize SIMD. 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 pe…

My first thought was conditional branches inside the for loop based on the element as well. By any chance, do you know how hard it is for compilers to auto-vectorize something like this? I am generally not sure where the boundary is.

GCC can do better than the example I gave.

https://godbolt.org/z/fo74G7d3W

Re: Push Ifs Up and Fors Down

#118

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…

My mental model: align with the world the very specific code I'm writing lives in. From domain specifics, to existing patterns in the codebase, to the stage in the data pipeline I'm at, performance profile, etc.

I used to try and form these kinds of rules and heuristics for code constructs, but eventually accepted they're at the wrong level of abstraction to be worth keeping around once you write enough code.

It's telling they tend to resort to made up function names or single letters because at that point you're setting up a bit of a punching bag with an "island of code" where nothing exists outside of it, and almost any rule can make sense.

-

Perfect example is the "redundancies and dead conditions" mentioned: we're making the really convenient assumption that `g` is the only caller of `h` and will forever be the only caller of `h` in order to claim we exposed a dead branch using this rule...

That works on the island, but in an actual codebase there's typically a reason why `g` and `h` weren't collapsed into each other to start.

Re: Push Ifs Up and Fors Down

#119

> If there’s an if condition inside a function, consider if it could be moved to the caller instead This idle conjecture is too rife with counterexamples. - If the function is called from 37 places, should they all repeat the if statement? - What if the function is getaddrinfo , or EnterCriticalSection ; do we push an if out to the users of the API? I think that we can only think about this transformation for interna…

[deleted]

Re: Push Ifs Up and Fors Down

#120
In some cases the difference between if and for is not as clear-cut. A for loop over an option? Likely rather to be considered as an if. What about length-limited arrays, where the iteration mainly occurs as a way to control whether executions occurs at all?
Post reply on HN