Hacker News new | ask | show | jobs
by gumby 971 days ago
I often write my code pessimally in this regard so have a note in the back of my mind to someday use these in a few hot paths.

When I say “pessimally” I mean I usually check the unlikely cases right away and then put the normal case last:

    Blah foo (something& arg) {
    
      if (is_invalid  (arg)) return blah(0);
      if (is_inactive (arg)) return blah(1);
    
    // ok do all the normal stuff
    }
It makes the code clearer but slightly slower. I could always write a conditional for the hot path up front, but code is for human readers, right?

So when people say “this clutters the code” they are right, but most of the time you just don’t worry about it — it need only clutter a few functions in your hot loops, where you’re willing to rewrite it anyway regardless of how ugly it gets.

It’s like looking at the standard library source: super cluttered, but it has to handle all sorts of weird corner cases and is called a lot. Normal code can ignore all that in more than 99.99% of the cases.

4 comments

Names like 'is_invalid' and 'is_inactive' will lead to a double negation.
Agreed, this reads so much easier...

  if (!is_valid)

  if (!is_active)
> I could always write a conditional for the hot path up front, but code is for human readers, right?

Does C or C++ actually make any promises that it’ll assume the “true” branch of the conditional will be taken? I always assumed that the compiler could make whatever weird decision it wants for that sort of thing.

TBH I’d probably just write normal stuff as a function, and then call that function directly in cases where performance is really crucial, if it can be done safely… if such a case exists…

No. The traditional compiler heuristic is to assume backwards branches are taken (loops) and forward branches are not.
I'm so confused by this. How would you avoid doing these checks? Aren't they invariants for your function?
I don’t think they suggested avoiding the checks, unless I’ve missed something?
The part that's confusing me is the part about avoiding clutter – if you have to do all the checks anyway, what clutter are you avoiding by changing the order of them?
That conditional would be checked, then if it failed, checked again after the normal case has run, in order to choose the arm to follow.

Not a huge deal execution-time-wise, but from a reader’s PoV, the way I write it says, “ok, the special cases don’t apply to the body so I don’t have to worry that the index will be out of range (or whatever) and can just focus on the logic”.

I believe the likelihood annotations are the things they are talking about, for cluttering the code. Not the argument checks.
Maybe the implied question is that, the compiler can optimise the checks to the occur in whatever order it wants.
> I usually check the unlikely cases right away and then put the normal case last.

Don't we all?

If only I lived in such a paradise!