_______ __ _______
| | |.---.-..----.| |--..-----..----. | | |.-----..--.--.--..-----.
| || _ || __|| < | -__|| _| | || -__|| | | ||__ --|
|___|___||___._||____||__|__||_____||__| |__|____||_____||________||_____|
on Gopher (inofficial)
URI Visit Hacker News on the Web
COMMENT PAGE FOR:
URI C++26: A User-Friednly assert() macro
wpollock wrote 3 hours 55 min ago:
> assert(x > 0 && "x was not greater than zero");
Shouldn't that be "||" rather than "&&"? We want the message only if
the boolean expression is false.
puschkinfr wrote 3 hours 42 min ago:
No, because the string will be implicitly converted to `true` and `(a
&& true) == a` (for boolean `a`), so it will only be `false` if the
assertion fails. Using || would always evaluate to `true`
wpollock wrote 1 hour 44 min ago:
You're right, thanks!
This works too (but I wouldn't recommend it):
assert( someBooleanExpression || ! "It is false" );
WalterBright wrote 3 hours 56 min ago:
D just makes assert() part of the language: [1] The behavior of it can
be set with a compiler switch to one of:
1. Immediately halting via execution of a special CPU instruction
2. Aborting the program
3. Calling the assert failure function in the corresponding C runtime
library
4. Throwing the AssertError exception in the D runtime library
So there's no issue with parsing it. The compiler also understands the
semantics of assert(), and so things like `assert(0)` can be recognized
as being the end of the program.
URI [1]: https://dlang.org/spec/expression.html#assert_expressions
adzm wrote 5 hours 23 min ago:
One of my favorite things from ATL/WTL was the _ASSERT_E macro which
additionally converts the source expression to text for a better
message to be logged
grokcodec wrote 7 hours 27 min ago:
Friedns shouldn't let Freidns post on HN without running spell check
semiinfinitely wrote 7 hours 43 min ago:
"C++47: Finally, a Standard Way to Split a String by Delimiter"
einpoklum wrote 5 hours 14 min ago:
A standard way to split a string? Well, what's wrong with:
std::views::split(my_string, delimeter)
?
nananana9 wrote 5 hours 8 min ago:
Template bloat, terrible compile errors, terrible debug build
performance, 1 second of extra compile time per cpp file when you
include ranges, and you can't step through it in a debugger.
fc417fc802 wrote 20 min ago:
> you can't step through it in a debugger.
What do you mean by that?
porise wrote 6 hours 35 min ago:
I'm still waiting for C++ to support Unicode properly.
amelius wrote 7 hours 46 min ago:
Shouldn't the preprocessor be fixed, if it trips that easily on common
C++ constructs?
marginalia_nu wrote 7 hours 26 min ago:
Preprocessor is just doing text transformations on the sources.
It's not really something that can be fixed, other than moving away
from the preprocessor and putting metaprogramming capabilities into
the language itself (which C++ has been doing).
amelius wrote 5 hours 59 min ago:
I mean, you could extend it such that a simple comma has no special
meaning.
But I agree, fewer special tricks is better and that includes the
preprocessor.
tom_ wrote 7 hours 43 min ago:
I'm sure the standardization committee are always looking for fresh
ideas!
throwpoaster wrote 7 hours 47 min ago:
assert(spellcheck(âFriednlyâ));
nananana9 wrote 5 hours 5 min ago:
spellcheck.cpp:1:19: error: unexpected character
1 | assert(spellcheck(âFriednlyâ));
| ^
MontagFTB wrote 8 hours 36 min 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.
saagarjha wrote 23 min ago:
I actually feel like asserts ended up in the worst situation here.
They let you do one line quick checks which get compiled out which
makes them very tempting for those but also incredibly frustrating
for more complex real checks youâd want to run in debug builds but
not in release.
bluGill wrote 3 hours 6 min ago:
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.
andrepd wrote 3 hours 45 min ago:
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.
samiv wrote 5 hours 57 min ago:
That's why you define your own assert macro and keep in on
unconditionally. Your programs will be better for it.
jandrewrogers wrote 5 hours 33 min ago:
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.
samiv wrote 5 hours 25 min ago:
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.
maccard wrote 6 hours 14 min ago:
Indeed.
bool is_even(int* valPtr) {
assert(valPtr != nullptr);
return *valPtr % 2;
}
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]
URI [1]: https://dev.epicgames.com/documentation/en-us/unreal-engine/...
secondcoming wrote 3 hours 54 min ago:
Let's not vague post on HN. What's the problem with the above?
saagarjha wrote 25 min ago:
The problem is the code unconditionally dereferences the pointer,
which would be UB if it was a null pointer. This means it is
legal to optimize out any code paths that rely on this, even if
they occur earlier in program order.
aw1621107 wrote 13 min ago:
> The problem is the code unconditionally dereferences the
pointer, which would be UB if it was a null pointer.
Only when NDEBUG is defined, right?
mhh__ wrote 5 hours 17 min ago:
This is a very "Dr Dr it hurts when I do this" "Don't do that" one
it must be said.
dccsillag wrote 6 hours 0 min ago:
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.
dataflow wrote 2 hours 56 min ago:
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.
IshKebab wrote 2 hours 4 min ago:
Assert doesn't work like that in any language.
comex wrote 1 hour 57 min ago:
It does in Rust: assert is always enabled, whereas the
debug-only version is called debug_assert.
But yes, âassertâ in most languages is debug-only.
IshKebab wrote 5 hours 47 min ago:
There's nothing wrong with it. It does exactly what you think it
does when passed null.
usrnm wrote 7 hours 10 min ago:
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.
nealabq wrote 7 hours 13 min ago:
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.
toxik wrote 6 hours 27 min ago:
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.
nealabq wrote 3 hours 27 min ago:
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.
jmalicki wrote 8 hours 0 min ago:
Side effects are bad of course, but anything beyond a straight
boolean or equality is bad?
`assert(vector.size() < 3)` is ridiculous to you?
nyc_pizzadev wrote 8 hours 10 min ago:
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.
URI [1]: https://github.com/fiberfs/fiberfs/blob/7e79eaabbb180b0f1a79...
omoikane wrote 7 hours 54 min ago:
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.
URI [1]: https://github.com/abseil/abseil-cpp/blob/0093ac6cac892086...
URI [2]: https://github.com/abseil/abseil-cpp/blob/0093ac6cac892086...
nmilo wrote 4 hours 12 min ago:
If your assert compiles down to `if (condition) {}` in production
then the compiler will optimize away the condition while keeping
any side effects.
IshKebab wrote 2 hours 2 min ago:
Yeah which may not be what you want. E.g.
`assert(expensive_to_compute() == 0)`.
The correct way to solve this is with debug asserts (as in
Rust, or how the parent described).
nyc_pizzadev wrote 57 min ago:
Genuine question, does Rust know if `expensive_to_compute()`
has side effects? There are no params, so could it be
compiled out if the return value is ignored? Ex:
`expensive_to_compute()` What about: `(void)
expensive_to_compute()`?
omoikane wrote 8 hours 48 min ago:
> (assert) doesn't follow the usual SCREAMING_SNAKE_CASE convention we
associate with macros
There are a few things like that, for example: [1] - isnan is an
implementation defined macro. [2] - `getc` may be implemented as a
macro, but often it's a function.
URI [1]: https://en.cppreference.com/w/c/numeric/math/isnan
URI [2]: https://en.cppreference.com/w/c/io/fgetc
nealabq wrote 7 hours 18 min ago:
In C++ you should probably #include instead of unless you have a
good reason. And especially avoid #including both. provides the
function std::getc(..) while usually provides getc(..) as a macro.
htons(..) and related socket-utility names are also often macros, but
I'm pretty sure there is not a std::htons(..) in the C++ standard,
partly because 'htons' is not an attractive name. Since it's
(sometimes) a macro don't qualify its namespace like ::htons(..).
A long time ago in the Microsoft C (and later C++) dev envs there
were macros named "min" and "max", which I thought were terrible
names for macros.
adzm wrote 5 hours 25 min ago:
> A long time ago in the Microsoft C (and later C++) dev envs there
were macros named "min" and "max", which I thought were terrible
names for macros.
Yeah, this is still in windows.h unless you #define NOMINMAX
I remember having to guard against this in some inline code by
surrounding the c++ calls with parenthesis, eg `(std::min)(a, b)`
nananana9 wrote 5 hours 18 min ago:
Yep. There's tons of others as as well. 16-bit x86 enjoyers will
be happy to know there are `near` and `far` macros whose primary
purpose in 2026 is to break my projection matrices. And of course
every Win32 function that takes strings has a macro that resolves
it to either the UTF-16 or ASCII variant, so your custom
CreateWindow is now a CreateWindowA, tough luck buddy.
I usually wrap Windows.h in a header followed by 100 #undefs to
contain the disease.
nyc_pizzadev wrote 9 hours 10 min ago:
The nice thing about assert() is you can just define your own: [1] In
this case, the ability to see the actual values that triggered the
assert is way more helpful.
URI [1]: https://github.com/fiberfs/fiberfs/blob/7e79eaabbb180b0f1a7942...
BoingBoomTschak wrote 7 hours 47 min ago:
Yeah, but the macro system being so pitiful makes me long for one
that allows something as magical as fiveam's is ( [1] ) instead of
having to write special cases for unary and binary predicates.
URI [1]: https://github.com/lispci/fiveam/blob/e43d6c8e7da5a80d5c33e8...
DIR <- back to front page