C++, move aside?

Andreas Hohmann July 31, 2024 #c++ #programming #move #rust

I recently read Nicolai Josuttis's book about C++ move semantics. It's an excellent book. Detailed, well organized, and full of good explanations and thoughfully arranged diagrams that present all the intricate details of C++ move semantics as clearly as possible. I didn't expect it, but I would even say that I enjoyed reading this book of about 250 pages about a single C++ feature. I will forever remember that moved-from objects are "in a valid but unspecified state". I also learned to appreciate the difficulty of introducing such as fundamental feature into an existing language at a relatively late stage without breadking backwards compatibility. There are a few quirks (such as the really confusing reuse of the rvalue reference syntax for universal references that Josuttis points out as well), but overall the specification is truly impressive in this area.

Compare this to Rust: move semantics are the default, a move is always (at least logically) a binary copy, and moved-from objects cannot be accessed. Clear and simple. Rust's "move as default" initially took me by surprise, especially because one typically starts with types that are "Copy" such as numbers, but quickly became second nature. One may need a chapter about the borrow checker, but definitely not a whole book about Rust's move semantics.

I think this is a crucial difference between the two languages. Rust is not easy, but its complexity reflects to are large extent the actual difficulties of the problem domain such as ownership and lifetimes in the context of asynchronous code (without a garbage collector). Not burdened by backwards compatibility with C, Rust can focus on and solve these real challenges.

Looking back, this seems to be one of the main issues with C++. There was always yet another technical challenge to overcome, yet another core language feature to introduce (for example, lambdas, concepts, coroutines). With all this focus on the language itself, everything around it has never reached the maturity that we now take for granted for any new language, be it good error messages, a standard module and build system, or universally accepted third party libraries (such as serde and tokio).

I still like C++, partly because I love the idea of zero-cost abstractions, and partly because it brings back fond memories of my early career (and struggles with the template support of the early C++ compilers). I'm also not a big fan of Rust's syntax: Why would anyone use a different syntax for closures and functions these days? However, the overall design, tooling, standard library, and huge collection of high quality third party packages are just too compelling.

Why would I spend even more time accumulating knowledge about artifically complex features if there is a clear alternative? As long as I'm paid for that, it's OK (and I recommend Josuttis's book), but otherwise it's hard to justify.