3 ms·
But if you spell that `assert(false)` instead of as a comment, the intent is equally clear, but the behavior when you're wrong is well-defined.
by addaon 10mo ago
But if you spell that `assert(false)` instead of as a comment, the intent is equally clear, but the behavior when you're wrong is well-defined.
- eterm 10mo agoBetter yet, `assert(false, message)`, with the message what you would have written in the comment.
- addaon 10mo ago`assert(false)` is pronounced "this can never happen." It's reasonable to add a comment with /why/ this can never happen, but if that's all the comment would have said, a message adds no value.
- eterm 10mo agoOh I agree, literally `assert(false, "This cannot happen")` is useless, but ensuring message is always there encourages something more like, `assert(false, "This implies the Foo is Barred, but we have the Qux to make sure it never is")`. Ensuring a message encourages people to state the assumptions that are violated, rather than just asserting that their assumptions (which?) don't hold.
- breatheoften 10mo agowhat language are we talking about? If it's cpp then the pronounciation depends on compiler flags (perhaps inferred from CMAKE_BUILD_TYPE)
- andrewf 10mo agoSwap the parameters around for C++ and similar langs where `assert(a, b)` evaluates the same as `(void) a; assert(b)`.
- JohnFen 10mo agoI agree that including that assert along with the comment is much better. But the comment alone is better than nothing, so isn't without value.
- zffr 10mo agoAt least on iOS, asserts become no-ops on release builds
- addaon 10mo agoYou can (and probably should) undef NDEBUG even for release builds.
- josephg 10mo agoIt really depends on the language you use. Personally I like the way rust does this: - assert!() (always checked), - debug_assert!() (only run in debug builds) - unreachable!() (panics) - unsafe unreachable_unchecked() (tells the compiler it can optimise assuming this is actually unreachable) - if cfg!(debug_assertions) { … } (Turns into if(0){…} in release mode. There’s also a macro variant if you need debug code to be compiled out.) This way you can decide on a case by case basis when your asserts are worth keeping in release mode. And it’s worth noting, sometimes a well placed assert before the start of a loop can improve performance thanks to llvm.
- addaon 10mo ago> debug_assert!() (only run in debug builds) debug_assert!() (and it's equivalent in other languages, like C's assert with NDEBUG) is cursed. It states that you believe something to be true, but will take no automatic action if it is false; so you must implement the fallback behavior if your assumption is false manually (even if that fallback is just fallthrough). But you can't /test/ that fallback behavior in debug builds, which means you now need to run your test suite(s) in both debug and release build versions. While this is arguably a good habit anyway (although not as good a habit as just not having separate debug and release builds), deliberately diverging behavior between the two, and having tests that only work on one or the other, is pretty awful.
- josephg 10mo agoI hear you, but sometimes this is what I want. For example, I’m pretty sure some complex invariant holds. Checking it is expensive, and I don’t want to actually check the invariant every time this function runs in the final build. However, if that invariant were false, I’d certainly like to know that when I run my unit tests. Using debug_assert is a way to do this. It also communicates to anyone reading the code what the invariants are. If all I had was assert(), there’s a bunch of assertions I’d leave out of my code because they’re too expensive. debug_assert lets me put them in without paying the cost. And yes, you should run unit tests in release mode too.
- fwip 10mo agoI think you might have missed that they threw an exception right under the comment.