Chris (2023-03-16 20:58:44) Permalink
In my Rust app I also define a custom “soft_assert” macro, which panicks in debug mode and silently reports a warning to Sentry in release mode. I was introduced to this pattern at Stripe, for situations of the shape “I don’t think this ever happens, and if it does it’s not worth blocking what the user is doing, but I want to know about it.”

` (2023-03-17 03:18:42) Permalink
Well in C if you can have a global variable debugging (true iff you're in debug assertion mode) can't you write something like

assert debugging ==>  (youngest >= 0); 

or at least you could if you also had a shortcut implication operator. Which you don't but you could switch to the inverse variable, running and write

assert running ||  (youngest >= 0);

which isn't quite as nice but would work. Perhaps release is a better name than running.

Trevor (2023-03-17 06:17:06) Permalink
In Scala and similarly Kotlin, this distinction exists with assert() vs require(), although here it's assert() which is usually disabled during release builds and require() which cannot be disabled.

James Noble (2023-03-17 07:14:07) Permalink
Dafny recently introduced a similar distinction: requires preconditions will be omitted if the analysis doesn't require the; while recommends preconditions will always be dynamically checked. See: "Specifying the Boundary Between Unverified and Verified Code." David R. Cok & K. Rustan M. Leino in LNC13360.

Aristotle Pagaltzis (2023-03-18 02:20:40) Permalink
Full well aware this is a bikeshed painting exercise, I’ll mention that the first thing that came to mind was assume() for debug-only assertions and assert() for always-on assertions. Now that I’ve seen the other comments, I’m thinking a better symmetry might be to call them assume() and require(). A nice aspect of this naming is that when documenting it you get to write that “debug mode checks your assumptions”.