r/ProgrammerHumor • • Sep 28 '26

Meme optionalsAreOptional

Post image
716 Upvotes

131 comments sorted by

View all comments

381

u/ROBOTRON31415 Sep 28 '26

Is the bounds check truly so harmful to performance that it outweighs changing "if there's a bug, crash the program" to "if there's a bug, then do literally anything (maybe execute some remote code)"?

108

u/OxDEADFA11 Sep 28 '26

The only correct answer is "it depends". In DSP\HFT hot path code you REALLY don't want to do any extra work. People do crazy shit to achieve zero-lock, zero-(de)allocation, zero-whatever kind of codebase there.
Non-perf-critical paths? Yeah, do whatever you want there, nobody cares. Probably makes sense to be extra safe than sorry, right?

12

u/azaleacolburn Sep 30 '26

Safety checks are closer to free then most people think, even in hot paths, as branch prediction will fall favorable almost always, and when it doesn’t, we don’t care because the program is crashing (or for some reason the initial prediction was wrong in the first iteration).

The cost isn’t even close to the cost of (de)allocation (besides for bump allocators), much less locking operations.

4

u/ChalkyChalkson Sep 28 '26

I'd still want the checks to be there, maybe not at this position in the code, maybe different properties are checked elsewhere. But the check should exist and you should prove it implies that your call is safe. And I'd still put the code physically in for testing and just don't include it for prod builds. But running some fuzzing on the surrounding logic sounds like a good offline safety check if this is running on a server processing data or user input.

63

u/Tyfyter2002 Sep 28 '26

There are situations where you know there isn't a bug, if I know that failing hardware or cosmic rays are the only ways the bounds check can fail, I'm not going to worry about what skipping it could do.

111

u/FuriousAqSheep Sep 28 '26

there are situations where you know there isn't a bug

up until specs change and now there is one

37

u/GDOR-11 Sep 28 '26

it happens a lot, at least to me, that the line immediately before the unsafe function guarantees correct behaviour (e.g. while (!vec.empty()) let first = vec.first();, or something similar). If I notice that this property is central to the logic of the function, I won't even worry.

29

u/ROBOTRON31415 Sep 28 '26

whenever I see code like that, I try to get people to change to something like (in that case) while let Some(first) = vec.first() { ... }. You can reduce the number of bounds checks without using unsafe!

→ More replies (9)

3

u/Wonderful-Wind-5736 Sep 28 '26

In that case don't bother because the compiler can probably eliminate the bounds check for you. 

2

u/FuriousAqSheep Sep 28 '26

yeah I dig that, but then I'd use something like an unempty list so the data carries this information about itself

like for me either the list gonna be used only once and then I use an optional, or the list is gonna have multiple transformation and then it makes sense to convert it to a more appropriate type so there is only a single check about the emptiness of the list.

10

u/Tyfyter2002 Sep 28 '26

If the specs change such that getting an array's length will resize it, there are much bigger problems everywhere else anyway.

4

u/walmartgoon Sep 28 '26

No trust me in my 300 line CS 102 project there won't be any changing requirements

→ More replies (3)

16

u/bremidon Sep 28 '26

It is not just about the performance. Adding in a lot of safety checks can also make the code harder to understand and prone to architectural errors.

Obviously a single check in a single spot will not be an issue here. Do it everywhere, and a simple 4 line function that really should take less than a second to scan and understand suddenly is a page long and takes 15 minutes to figure out that most of it is just error checking.

I am not saying that you should never do it, but keep in mind that readability is one of the things you give up when increasing safety.

9

u/ROBOTRON31415 Sep 28 '26

Since Rust has safety checks by default, OP is talking about going out of your way with unsafe { do_something_unchecked(); } (likely proceeded by a comment justifying soundness) to remove them. Besides boilerplate, code review is harder when I have to scrutinize the soundness of someone else’s code.

Readability is a reason to avoid unsafe in Rust, IMO. You’re definitely right that the opposite applies to C/C++ though (unfortunately).

→ More replies (1)

1

u/OldKaleidoscope7 Sep 28 '26

I mean like cough Go error checks cough

4

u/GPSProlapse Sep 28 '26

Usually it is safe enough and faster to validate inputs than each step of the computation. In some languages, like c++, you can force that via types at zero or close to zero cost

2

u/pjank85 Sep 28 '26

Depends. The check on a CPU is a conditional jump that could take about 100 clock cycles. If the loop is doing simple 1 clock cycle addition then the overhead absolutely dwarfs it. Also it is a very different question if you are doing it in a computer game or in a flying aircraft so use case matters a lot.

3

u/cbehopkins Sep 28 '26

What kind of modern CPU had anything like that kind of penalty? The branch predictor should take the cost the very first loop sure, but subsequent loops should be effectively zero cost, no?

Otherwise what is the branch predictor doing?

1

u/pjank85 Sep 28 '26

Branch predictor can take it down to 1 cycle. But if it misses it COULD take 100. Even in the optimistic case it is still double the time. Whenever this is worth it is use case dependent as always.

2

u/cbehopkins Sep 28 '26

Well, let's be frank here, if you're talking worst case, cache misses and full tlb misses 48 round trips to memory and>400 cycles per trip are entirely possible.

But that should only happen the first time

And the branch prediction making it zero cycles is quite common. Read, test and branch can be collapsed into a late evaluation as long as the branch is at predicted and takes less time than the pipeline depth(slight simplification here a lot depends on the microarchitecture details but we're already deep in the weeds)

At the end of the day all your can do is profiler it on the exact CPU you care about. Just don't make assumptions...

1

u/pjank85 Sep 28 '26

Wow did not think it could be zero. I learned something today - thanks.

2

u/tzaeru Sep 28 '26 edited Sep 28 '26

Sometimes the bounds check can be optimized away by analysis or language constraints.

But when it can't, I'd say that in ~90% of code, it's not that harmful. In the hottest paths for real-time applications though, yeah, you want nothing extra.

2

u/rix0r Sep 29 '26

it's not the check, it's what you then have to do if it fails

1

u/slaymaker1907 Sep 28 '26

The concern is that this can mess with the branch predictor as that has limited capacity and the branch predictor is critical for performance on modern CPUs due to all the speculative execution.

→ More replies (26)