STX  1.0.0
STX Documentation

What is STX?

STX is a collection of libraries and utilities designed to make working with C++ easier and less error-prone. This includes but is not limited to well-proven and widely adopted paradigms, data-structures, and designs from other prominent projects and programming languages accross the software engineering community.

At the core, all STX libraries are no_std . No RTTI, memory allocation, nor exceptions.

STX Libraries

Panic Library

See guide on Panicking

The panic library provides:

Error and Optional-Value Handling Library

These monadic types not only make error handling easier but also make the paths more obvious to the compiler for optimizations. Monads can be simply thought of as abstract types of actions. Their monadic nature makes it easy to operate on them as pipelines and in the process eliminate redundant error-handling logic code.

Backtracing Library

The backtracing library is useful for manually querying/viewing information of active stack frames. It makes debugging easier by making it easier to get stackframe information programmartically or automatically (via panics) without having to inspect core dumps or step into a debugger in which errors might not be reproducible (especially for embedded systems). The backtrace library is disabled by default as not all platforms support them, It can be enabled by setting STX_ENABLE_BACKTRACE to ON in the CMakeLists.txt file, this is demonstrated in the panic_backtrace example project.

Why STX?

STX is primarilly an effort to bring a more convenient and usable error-handling model to the C++ ecosystem. Whilst also sampling ideas from various error-handling model implementations duplicated across the community, Most of the basic facilities for which STX's libraries aims to provide.

Here is a list of C++ projects with a similar error-handling model:


These reasons are a bit biased, but based on my team's experience:

Some Interesting Reads

Relatable Excerpts

This problem isn’t theoretical. I’ve encountered numerous bugs caused by ignoring return codes and I’m sure you have too. Indeed, in the development of this very Error Model, my team encountered some fascinating ones. For example, when we ported Microsoft’s Speech Server to Midori, we found that 80% of Taiwan Chinese (zh-tw) requests were failing. Not failing in a way the developers immediately saw, however; instead, clients would get a gibberish response. At first, we thought it was our fault. But then we discovered a silently swallowed HRESULT in the original code. Once we got it over to Midori, the bug was thrown into our faces, found, and fixed immediately after porting. This experience certainly informed our opinion about error codes.

In the exception model, any function call – and sometimes any statement – can throw an exception, transferring control non-locally somewhere else. Where? Who knows. There are no annotations or type system artifacts to guide your analysis. As a result, it’s difficult for anyone to reason about a program’s state at the time of the throw, the state changes that occur while that exception is propagated up the call stack – and possibly across threads in a concurrent program – and the resulting state by the time it gets caught or goes unhandled.

Bugs Aren’t Recoverable Errors!

Relatable Excerpts

Many projects ban exceptions. In SC++F 2018, 52% of C++ developers reported that exceptions were banned in part or all of their project code i.e., most are not allowed to freely use C++’s primary recommended error-handling model that is required to use the C++ standard language and library.

A programming bug or abstract machine corruption is never an "error" (both are not programmatically recoverable, so report bugs to the human programmer using contract violations that default to fail-fast and report abstract machine corruption using fail-fast). Programming bugs (e.g., out-of-bounds access, null dereference) and abstract machine corruption cause a corrupted state that cannot be recovered from programmatically, and so should never be reported to the calling code as errors that code could somehow handle.

Note here that exceptions also don't fit this fail-fast procedure as they can be caught by any function on the stack! and try to continue the program!!! (for fail-fast: STX provides stx::panic, and for recoverable errors: stx::Result). There should be no reason to continue the program or propagate a programming bug.

Today's dynamic exception handling is not deterministic (run-time space and time determinism). This is the primary reason exceptions are banned in many real-time and/or safety-critical environments (for example, many games, coding standards like JSF++ [JSF++2005], and environments like the Mars Rover flight software [Maimone 2014]).

We cannot accept that "Standard C++ is not applicable for real-time systems" – that would be an admission of defeat in C++'s core mission as an efficient systems programming language. Therefore we know we cannot live with today's model unchanged.

"[In CLU] We rejected this approach [propagating dynamic exceptions] because it did not fit our ideas about modular program construction. We wanted to be able to call a procedure knowing just its specification, not its implementation." – [Liskov 1992]

"By allowing multi-level propagation of exceptions, C++ loses one aspect of static checking. One cannot simply look at a function to determine which exceptions it may throw." – [Stroustrup 1994] p. 395