Posts

CW_USEDEFAULT: An underappreciated UX feature

Say you're writing code for a desktop PC application. It's very common for people to have multiple displays/screens for their desktop setups nowadays. When the user launches your program, how do you know which screen it should appear on to provide the least-jarring user experience? Many applications seem to get this wrong, opting for whatever display happens to be set as primary, or for whatever display the program was last closed on, or whatever screen there happens to be a mouse pointer on, either at some arbitrary time after the app started executing its code or each time it gets around to creating a window. While those approaches would make for good choices that the user can pick between in your app's settings, they're all poor defaults and even worse for the first-launch experience. It's actually a trick question. The correct answer is to let the window manager decide. That can vary based on operating system and desktop environment, but the general principle ...

What if C++ had explicit destruction?

Scope-based lifetime is a fantastic language feature, and it's a large contributing factor to the popularity of languages like Rust. C++ calls it RAII for historical reasons, but the general idea is that the compiler automatically inserts calls to cleanup functions (destructors) at the instant when the object ceases to be accessible (goes out of scope). This works very well for a wide variety of object types, such as allocated memory, operating system handles (e.g. files), locks/mutexes, logging, and more. The primary strength here is that the compiler doesn't let us forget to do a necessary operation. However, destructors in C++ are also incredibly limited compared to how they could be. They cannot take any parameters, and they cannot fail. You can of course add interfaces to set parameters in advance or to explicitly clean up before the destructor so you can check for failures, but those are things that can be forgotten. The compiler always remembers to call the destructor...

The curious case of the coroutine that couldn't be killed

Coroutines are a C++20 feature I've fallen in love with recently, especially in the context of asynchronous programming. They certainly take a lot of boilerplate to initially set up, but once you've got that working, async code can be written in a style that looks very similar to synchronous blocking code, making it easier to read and reason about. It's not a perfect honeymoon though, there are some hidden gotchas that can ruin your day, but they can be worked around. People are often surprised at how coroutines and lambdas interact for example, but that's really the only outcome that makes sense given lambdas can be invoked multiple times. Today though we're going to look at how coroutines and C++ exceptions interact, and what that means for our behind-the-scenes code. Let's start with this basic minimal template, which we'll be making repeated changes to throughout this post: Wrap lines #include <array> #include <cassert> #includ...