Live data from Hacker News

Push Ifs Up and Fors Down

matklad.github.io

151–160 of 209 posts

Re: Push Ifs Up and Fors Down

#151
post #130

Earlier quoted context omitted.

> If the function is called from 37 places, you need to refactor your code, Really? I do not have to think hard before I have a counter exampl: authentication I call authenticate() is some form from every API All 37 of them

If you are explicitly calling authenticate() for each api, you’re doing it “wrong”. At that point you want implied authentication not explicit authentication. Why not move it to some middleware that gets called in every api call?

Because then you are calling middleware_caching_auth_broker() from 37 places instead of authenticate(). Just the name has changed, not the 37.

Re: Push Ifs Up and Fors Down

#152

Code complexity scanners⁰ eventually force pushing ifs down. The article recommends the opposite: By pushing ifs up, you often end up centralizing control flow in a single function, which has a complex branching logic, but all the actual work is delegated to straight line subroutines. ⁰ https://docs.sonarsource.com/sonarqube-server/latest/user-gu...

tangent: how did you get that superscript 0 to render in an HN comment?

Re: Push Ifs Up and Fors Down

#154
In my field (server programming) readability trumps them all.

Nested g() and h() can be much better if they are even just 1% easier to understand. No one cares about a few extra CPU cycles, because we don't write system or database code.

Re: Push Ifs Up and Fors Down

#155

Earlier quoted context omitted.

If you are explicitly calling authenticate() for each api, you’re doing it “wrong”. At that point you want implied authentication not explicit authentication. Why not move it to some middleware that gets called in every api call?

Because then you are calling middleware_caching_auth_broker() from 37 places instead of authenticate(). Just the name has changed, not the 37.

But that's ok because the calls are hidden from the programmer.

I'm not sure if my response is serious or tongue-in-cheek. Maybe a bit of both.

Re: Push Ifs Up and Fors Down

#156

Code complexity scanners⁰ eventually force pushing ifs down. The article recommends the opposite: By pushing ifs up, you often end up centralizing control flow in a single function, which has a complex branching logic, but all the actual work is delegated to straight line subroutines. ⁰ https://docs.sonarsource.com/sonarqube-server/latest/user-gu...

tangent: how did you get that superscript 0 to render in an HN comment?

HN allows many Unicode characters, including U+2070 superscript zero which I copy+pasted after a web search. I'd actually be interested to learn the full allowlist.

https://en.wikipedia.org/wiki/Unicode_subscripts_and_supersc...

Re: Push Ifs Up and Fors Down

#157
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.

Working with python for a while and I still don’t bother with classes. Only when I “borrow” other code do I mess with them. It just seems like a flowery way to organize functions. I prefer to just write the functions. Maybe its because my first languages lacked classes that I don’t much like to reach for them.

I don’t even like loops and prefer to functionalize them and run in parallel if sensible.

I know this makes me a bit of a python heathen but my code runs fast as a result.

Re: Push Ifs Up and Fors Down

#159

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…

This aligns nicely with how things look in the "small-step" flavour of PL theory / lambda calculus.

In the lingo, expressions are evaluated by repeatedly getting "rewritten", according to rules called reduction rules. e.g., (1 + 2) + 4 might get rewritten to 3 + 4, which would then get rewritten to 7.

There are two sorts of these rules. There are "congruence" rules, which direct where work is to be done ("which subexpression to evaluate next?"); and then there are "computation" rules (as Pierce [1] calls them), which actually rewrite the expression, and thus change the program state.

"Strict"/"non-lazy" languages (virtually every popular general-purpose language? except Haskell) are full of congruence rules – all subexpressions must be fully evaluated before a parent expression can be evaluated. The important exceptions are special constructs like conditionals and indefinite loops.

For conditionals in particular, a computation rule will kick in before congruence rules direct all subexpressions to be evaluated. This prunes the expression tree, now in a very literal sense.

[1]: Benjamin C. Pierce, Types and Programming Languages (recommended!)

Re: Push Ifs Up and Fors Down

#160

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

I feel this kind of critique, which I see often as a response to articles like this, is so easy as to be meaningless. How is one supposed to ever talk about general principles without using simplified examples?

Aren't you just saying "Real code is more complicated than your toy example"?

Well sure, trivially so. But that's by design.

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

Not really. He's just saying that when you push conditional logic "up" into one place, it's often more readable and sometimes you might notice things you otherwise wouldn't. And then he created the simplest possible example (but that's a good thing!) to demonstrate how that might work. It's not a claim that it always will work that way or that real code won't be more complicated.

Post reply on HN