Hello all,


I recently wrote my own freestanding replacement for the C++ standard library.  I'm one of those people who started writing out C++ on a 44Mhz processor and never was allowed to use the standard template library because it was too bloated. In many ways this code is the exact opposite of Boost in terms of its design. I'd like to share a few details with this list because I think it is interesting to talk about what could be done to improve the developer experience of the standard library. Please be warned, I have a lot of opinions about C++ and they are nonconformist.


In this email I would like to talk about asserts. I'd like to see a lot more features available than with pre/post/contract_assert.


I would argue there has to be support by default for making the debugger stop on the exact line where the assert fired. There is just no excuse for having a software engineer do unnecessary manual labour every time an assertion fires. And students shouldn't be asked to write this themselves when learning a new language. Currently only clang (and not gcc) can be configured to support this perfectly.


There are also uses for having different "levels" of severity when it comes to asserts. When I am cross compiling to an embedded target I am not going to be able to afford all the same assertions with all the same strings being added to the string table. At minimum that entails "debug asserts" and "release asserts" to differentiate between the two use cases. The code I am sharing also uses compile time string hashing in order to identify filenames when compiled for release. (This didn't work reliably with constexpr and you have to check the generated assembly to find that out.) Having these kinds of build levels is also common enough that CMake has it built in.


(As a slight aside, it would be nice to have support for string hashing in the elf file format. That way strings could be replaced by integers in the generated assembly and then the debugger could look up those strings in an optional string table. There is no reason to have a huge list of human readable names embedded in a stripped executable's string table when you are testing code on a 16-bit processor.)


Next is the issue of formatting assert messages. It turns out to be really handy to have debug asserts that take C-style variadic arguments and perform printf formatting. There is an issue here with having untested format strings and that does need to be resolved. However, by leveraging gcc's ability to check a printf format string against its arguments I was able to avoid any issues in my own work. This approach avoids making an unnecessary local function call or allocating memory after an assertion fails.


With that out of the way, let me show you some code.  This is a debug assert that implements the above:


#define hxassertmsg(x_, ...) (void)((bool)(x_) \

|| (hxloghandler(hxloglevel_assert, __VA_ARGS__), hxasserthandler(__FILE__, __LINE__)) \

|| hxbreakpoint())


The assert handler returns true when it wants a breakpoint set.


Next is a macro that implements a release assert at a higher release level. (hxstring_literal_hash uses some horrifying macros.) 


#define hxassertrelease(x_, ...) (void)((bool)(x_) \

        || (hxasserthandler(hxstring_literal_hash(__FILE__), __LINE__), 0))


The result is adding one function call with two integer parameters to the executable. This macro is also capable of printing formatted messages and setting breakpoints at lower release levels. This particular version uses a handler that is also marked noreturn.


There are more pieces of functionality needed. Any C++ library implementing asserts is going to want the compiler to know that the release mode assert handler or log handler cannot throw an exception. However, there is overhead associated with "noexcept" and it is just impossible to add that overhead everywhere an assert is used. This is something that still requires compiler intrinsics.


The standard library also has explicit language allowing for its asserts to operate in a manifestly const environment. It would be nice for others to be able to access that functionality without mucking up the callstack for every assert in the codebase.


If you made it this far, thank you. Here are some links if you want to know more. This is the main header file for the Hatchling Platform which has been my test bed and includes this code:


https://github.com/whatchamacallem/hatchlingplatform/blob/master/include/hx/hatchling.h


Here is the whole project and it has some overview docs. Please be kind, this is a solo effort that is just being released to the world and I am not trying to go head to head with the standard library over all the possible things.


https://github.com/whatchamacallem/hatchlingplatform/


Stay tuned and I'll put something else together about developer experience and micro-optimization. I am happy to write a formal proposal if anything resonates with the list.


Regards,

Adrian Johnston