5 ms·
I can't imagine error-checking if's being a source of slowness. How are exceptions generated in the first place? Using if's. And anyway, even well structured co
by jstimpfle 5y ago
I can't imagine error-checking if's being a source of slowness. How are exceptions generated in the first place? Using if's. And anyway, even well structured code is full of if's (e.g. array iteration), and it's not a problem. Especially for error-checking, when the error case is rare, the CPU will correctly predict the branch to take most of the time, so the cost of the if is negligible.
The only call where if's should probably be minimized is on hot paths, where there shouldn't be any I/O or other exception code anyway.
I would agree that manual stack unwinding (many stack frames deep) by propating error values up the call chain is bad. The problem here is not the if's, but that the program structure is unnecessarily convoluted. This can happen when specific code is calling generic code a lot (which can be avoided by having the generic code call the specific code instead).
> You are writing bad code, and should be ashamed.
Woah, calm your horses!
- ncmncm 5y agoThat "if" that guards the throw is the same "if" as would guard the error return. It is the second "if", in the caller, checking the returned result, that up-to-doubles your branch-prediction cache footprint. On, yes, the hot path. Program structure corruption is another problem. They add. Bad code is a tax on all of us.
- jstimpfle 5y agoWhich is what I said. And I still don't see how most code that potentially returns errors would be on a hot path. Code that is really on a hot path should probably not call into generic code anyway, and/or that called code should be inlined. I don't know, as a C programmer, somehow I rarely run into these situations where I have to check error return values. I think the reason is that I work hard to avoid wrappers around wrappers around wrappers. Mostly error checking is required when interacting with the OS - i.e. for I/O, which is not critical paths. A simple example would be memory allocation. A good C programmer allocates memory upfront. A bad C++ programmer could go, "eh, if it's so convenient I'll simply declare this std::vector locally, and if allocation fails it'll throw an exception and RAII and exceptions will solve the error handling issue magically without me having to type a single keystroke". Of course allocating each time is a lot slower than allocating only a single time upfront; no matter how much faster or convenient and individual allocation and error checking would be. This example shows how the perception of speed can often be warped because we're measuring the wrong thing entirely. What is bad code is often not clear cut, and neither is how to improve it.
- ncmncm 5y agoInlined code still has all the "if" checks of the original code, just without the actual "jsr" and "ret" instructions in between. Comparing a good C coder to a bad C++ coder is meaningless: By definition, a bad coder makes bad choices, whatever the language. Bad code is slow in a place where speed matters. It is improved by making it fast. Language choice does not affect this. What language choice does affect is whether you can afford to spend the attention needed to make the code fast. C++ provides tools to offload busywork, freeing your attention to apply to what matters. It remains the programmer's job to choose that.
- jstimpfle 5y agoI'm not sure what you had in mind, but this little example is compiled using a single test: https://godbolt.org/z/bcqPWEn4a https://godbolt.org/z/bcqPWEn4a I still can't imagine a situation where speed matters and where exceptional situations are likely and also hard to handle in a performant way with explicit error checking. Do you have any examples?
- ncmncm 5y agoIt suffices that exceptional situations are possible and must be checked for. It is true that in C++, as in Rust, it is much more common than in C to have very short functions that call other very short functions that, all composed together, do a job that, absent abstraction, might all be coded in a single larger function tailored to the specific use case; and the compiler squeezes out most of the calls and generates object code as if for that single, longer function. Therefore, there are many more places where an error return report would need to bubble up through, and that would cripple performance to handle the naive way, without exceptions. It might be that some languages that have a native "result" type, and automatically generate checking code at the call site, can squeeze out most of the intermediate-level checks when composing inline functions together, e.g. if actual errors mostly occur at leaf nodes of the call tree. That could mitigate the heavy overhead cost of the method. But I don't know if any compilers do such an optimization, or if they do, how well it really works. Coding an optimizer is hard.
- gumby 5y ago> I can't imagine error-checking if's being a source of slowness. The overhead of doing this is measured in the article itself.
- jstimpfle 5y agoAs far as I can see, only the overhead of throwing exceptions is measured. Not error-checking if's (which might be quite hard to measure).