Live data from Hacker News

Push Ifs Up and Fors Down

matklad.github.io

181–190 of 209 posts

Re: Push Ifs Up and Fors Down

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

Everyone has different opinions as this might be the printer driver on the PC or the printers internal circuit. The printer itself absolutely shouldn't try to spook the wheels when there is no paper. Id stick that check in the function!

Re: Push Ifs Up and Fors Down

#182

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

If the function is called from 37 places, you need to refactor your code, but to answer your question on that point: it depends. DRY feels like the right answer, but I think we'd have to review an actual code example to decide. On examples where you're talking about a library function, I think you have to accept that as a library you're in a special place: you're on an ownership boundary. Data is moving across domain…

I can't imagine a large program where no function is useful enough to be called more than 37 times. Memory allocation? Printing? Adding a member to a list? Writing to a file?

I'm guessing you mean something else, or do you feel useful functions can't be called many times in the same program?

Re: Push Ifs Up and Fors Down

#183
post #134
post #105

Earlier quoted context omitted.

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

And then at some point someone shows you how Classes can be verbs, and functions can be nouns, and your brain hurts for a while. You overuse that paradigm for a while, and eventually learn to find the appropriate balance of ideas.

Writing code is like writing though. None of these ideas for structuring code are the be all and end all of coding. Things evolve, sometimes old idea are good, sometimes new.

Like how the phrase “to boldly go where no man has gone before” will bring out pendants.

Re: Push Ifs Up and Fors Down

#184
post #174

Related: Within a function, I'm a fan of early bail out. While this goes against the usual advice of having the positive branch first, if the positive branch is sufficiently large you avoid having most of the function indented.

[deleted]

Re: Push Ifs Up and Fors Down

#185
post #174

Related: Within a function, I'm a fan of early bail out. While this goes against the usual advice of having the positive branch first, if the positive branch is sufficiently large you avoid having most of the function indented.

> having positive branching first This is advice I've never seen or received. It's always been the latter, exit early, etc. Languages like Swift even encode this into a feature, a la if guards.

Positive branch first is good advice when both branches are roughly even in terms of complexity. If the negative branch is just a return, I’d bail early instead.

Negative first makes else-branches double negative which reads weird, eg. if !userExists {…} else {…}

Re: Push Ifs Up and Fors Down

#186
Many variants of this debate play out in real-world systems: data pipelines, game engines, and large-scale web infra. The only universal law is that local code clarity must never be optimized at the expense of global throughput or maintainability. Pushing ifs up absolutely unlocks performance when you're dealing with a hot loop—early bailouts mean less work per iteration, and in my experience, that's often the difference between a scalable system and a bottleneck. But the real win is batch processing (pushing fors down): it's the only way you get cache locality, vectorization, and real-world performance on modern hardware. No amount of OOP purity or DRY dogma can change the physics of memory bandwidth or the nature of branch misprediction.

Re: Push Ifs Up and Fors Down

#187
post #134

Earlier quoted context omitted.

And then at some point someone shows you how Classes can be verbs, and functions can be nouns, and your brain hurts for a while. You overuse that paradigm for a while, and eventually learn to find the appropriate balance of ideas.

Writing code is like writing though. None of these ideas for structuring code are the be all and end all of coding. Things evolve, sometimes old idea are good, sometimes new. Like how the phrase “to boldly go where no man has gone before” will bring out pendants.

I don't believe that anyone wears pendants much on that show, unless you mean the communicators people wear in TNG. I did have a Romulan keychain once, though.

Re: Push Ifs Up and Fors Down

#188

Earlier quoted context omitted.

It sounds like self-inflicted boilerplate to me.

If you were going to write the tests anyway, the additional boilerplate for splitting it up and doing a wrapper isn’t so bad (in C at least, maybe it is worse for some language).

When you say "isn't so bad", is it just a manner of speech or is it actually a little bad (but it is a compromise?)?

Re: Push Ifs Up and Fors Down

#189
post #136

Earlier quoted context omitted.

> a database object exists, and creating it if not. Imagine your filesystem or database library either doesn't have an upsert function to do this for you, or else you can't use it because you want some special behaviour for new records (like writing the current timestamp or a running total, or adding an entry to a log file, or something). This is why databases have transactions. > simple example where you're checking…

Sure, I agree that a transaction should be used here (in the database example at least). But that's orthogonal to my point, or maybe even in favour of it: doesn't a transaction necessitate keeping the conditional close to the effect? It's a perfect example of what I'm trying to say, how do you make sure the conditional happens in the same transaction as the effect, while simultaneously trying to push the conditional…

By pushing up the transaction boundary. The only reason why the conditional is important is because it part of a larger sequence of operations that you want to complete in an atomic fashion.

Your transaction needs to encompass all of those operations, not just parts of it.

Re: Push Ifs Up and Fors Down

#190

Earlier quoted context omitted.

If you were going to write the tests anyway, the additional boilerplate for splitting it up and doing a wrapper isn’t so bad (in C at least, maybe it is worse for some language).

When you say "isn't so bad", is it just a manner of speech or is it actually a little bad (but it is a compromise?)?

Well, I was working on a sort of green-field project that did this, and I liked it. It neatly solved the problem of needing the tests, but only wanting to call them on user-provided inputs. However, some caveats:

* I wasn’t around long enough to see if there was a hidden maintenance cost

* It was a very thoughtfully designed library in an already-well-understood domain so it wasn’t like we were going to need to change the arguments a ton

* It was explicitly a library designed to be used as a library from the get-go, so there was a clear distinction of which functions should be user-visible.

I think I would find it annoying if I was doing exploratory programming and expected to change the arguments often. But, in that case, maybe it is too early to start checking user inputs anyway.

Post reply on HN