Comment by MontagFTB
7 hours ago
Putting code with side effects into an assert is asking for trouble. Compile with NDEBUG set and the effects mysteriously disappear! Anything beyond an equality expression or straight boolean should be avoided.
7 hours ago
Putting code with side effects into an assert is asking for trouble. Compile with NDEBUG set and the effects mysteriously disappear! Anything beyond an equality expression or straight boolean should be avoided.
Related our logging system has a debug which is not logged by default but can be turned on if a problem in an area is found (in addition to the normal error/info which is logged). I had the idea that if a test fails we should print all these debugs - easy enough to turn on but a number of tests failed because of side effects that didn't show up when off.
i'm trying to think of how/if we can run tests with all logging off to find the error and info logs with side effects.
I once spent several days debugging that same mistake. Stuff worked perfectly in tests but broke misteriously in production builds. Couldn't stop laughing for a few minutes when I finally figured it out.
That's why you define your own assert macro and keep in on unconditionally. Your programs will be better for it.
An assertion can be arbitrarily expensive to evaluate. This may be worth the cost in a debug build but not in a release build. If all of assertions are cheap, they likely are not checking nearly as much as they could or should.
Possibly but I've never seen it in practice that some assert evaluation would be the first thing to optimize. Anyway should that happen then consider removing just that assert.
That being said being slow or fast is kinda moot point if the program is not correct. So my advisor to leave always all asserts in. Offensive programming.
Indeed.
Does not do what you think it does with nullptr. A major game engine [0] has a toggle to enable asserts in shipping builds, mostly for this reason
[0] https://dev.epicgames.com/documentation/en-us/unreal-engine/...
This is a very "Dr Dr it hurts when I do this" "Don't do that" one it must be said.
Let's not vague post on HN. What's the problem with the above?
I'm sorry, but what exactly is the problem with the code? I've been staring at it for quite a while now and still don't see what is counterintuitive about it.
Depends on where you're coming from, but some people would expect it to enforce that the pointer is non-null, then proceed. Which would actually give you a guaranteed crash in case it is null. But that's not what it does in C++, and I could see it not being entirely obvious.
2 replies →
There's nothing wrong with it. It does exactly what you think it does when passed null.
This is just a symptom of a bad assert() implementation, which funny enough is the standard. If you properly (void) it out, side effects are maintained.
https://github.com/fiberfs/fiberfs/blob/7e79eaabbb180b0f1a79...
assert() is meant to be compiled away if NDEBUG is defined, otherwise it shouldn't be called assert(). Given that assert() may be compiled away, it makes sense not to give it anything that has side effects.
Abseil has the convention where instead of assert(), users call "CHECK" for checks that are guaranteed to happen at run time, or "DCHECK" for checks that will be compiled away when NDEBUG is defined.
https://github.com/abseil/abseil-cpp/blob/0093ac6cac892086a6...
https://github.com/abseil/abseil-cpp/blob/0093ac6cac892086a6...
If your assert compiles down to `if (condition) {}` in production then the compiler will optimize away the condition while keeping any side effects.
1 reply →
Side effects are bad of course, but anything beyond a straight boolean or equality is bad?
`assert(vector.size() < 3)` is ridiculous to you?
I don't mean to be that guy, but for "functional" programmers a print statement has "side effects".
But your meaning is clear. In an assert expression, don't call functions that might change the program/database state. Be as "const" as possible.
Not just for functional programmers. Prints and other I/O operations absolutely are side effects. That's not running counter to the point being made. Print in an assert and NDEBUG takes away that behavior.
You're right of course. I was thinking specifically of printing log/debug statements in the assert(..), but that usually only happens if the assert(..) fails and exits, and in that case the "no side effects" rule no longer matters.
Rust has assert and debug_assert, which are self-explanatory. But it also has an assert_unchecked, which is what other languages incl C++ call an "assume" (meaning "this condition not holding is undefined behaviour"), with the added bonus that debug builds assert that the condition is true.