_______               __                   _______
       |   |   |.---.-..----.|  |--..-----..----. |    |  |.-----..--.--.--..-----.
       |       ||  _  ||  __||    < |  -__||   _| |       ||  -__||  |  |  ||__ --|
       |___|___||___._||____||__|__||_____||__|   |__|____||_____||________||_____|
                                                             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