Welcome to my blog.

Imagine that you have been designing a programming language for over 30 years and that it gradually became widely used across the globe. Some of the decisions you made at the beginning were excellent and contributed to the success of your project. Some others, however, were not the best: over the years you and your users realized that the world would have been a better place if those choices you made eons ago were slightly different.

You keep evolving your language, adding useful features and keeping it up to speed with the competition. The bad choices and older (now obsolete) constructs still linger.

You try removing the most dangerous and least used aspects of the language, and while their dismissal is highly successful, some users will undoubtedly be hindered by it. For more popular constructs, you attempt deprecation: a large part of the community welcomes it and migrates their codebases, while another finds the work required to achieve conformance either unjustifiably large or impossible due to legacy dependencies or licensing issues.

It's been exactly 447 days since my last article, "compile-time iteration with C++20 lambdas". I should be ashamed.

In my defense, I've been very busy since then... and I'm going to tell you all about it in this blog post.

As my memory fades away more quickly due to getting older, I had to go through my various social media accounts to reconstruct a timeline of the most important events in these past months. While very convenient, I also have to admit that it is sort of scary to see how all my history is publicly available.

In one of my previous articles, "compile-time repeat & noexcept-correctness", I have covered the design and implementation of a simple repeat<n>(f) function that, when invoked, expands to n calls to f during compilation. E.g.

repeat<4>([]{ std::cout << "hello\n"; });

...is roughly equivalent to...

[]{ std::cout << "hello\n"; }();
[]{ std::cout << "hello\n"; }();
[]{ std::cout << "hello\n"; }();
[]{ std::cout << "hello\n"; }();

If you squint, this is a very limited form of compile-time iteration. When writing generic code, I've often needed similar constructs in order to express the following actions:

I'm back in London from Jacksonville, where I attended my first ISO C++ meeting. Apart from the long flights and long working hours, it has been a very enjoyable experience for multiple reasons:

• I was able to actively participate in the evolution of the language and influence it by voting and discussing;

• Seeing the amount of work, the engaging debates, and the formal procedures used to move C++ forward gave me a newfound appreciation for all the members of the committee and for the language;

Simon Brand (a.k.a. TartanLlama) recently published an article called "Functional exceptionless error-handling with optional and expected" where he excellently explains how sum types (e.g. std::optional and std::variant) can be used in lieu of exceptions in order to implement error handling.

The article focuses on the usage of std::optional, on std::expected, and on two monadic operations, map and and_then, which reduce boilerplate and increase readability of the code. While Simon briefly mentions the benefits of ADTs (algebraic data types) over exceptions, I think that the topic deserves more attention, as some readers missed the point.

Here's an example comment from the article's /r/cpp thread:

In my previous article ("abstraction design and implementation: repeat") I've shown how to implement a simple repeat(n, f) abstraction that invokes a FunctionObject f $$n$$ times in a row.

A large part of the article focused on adding a noexcept specifier to repeat that correctly propagated noexcept-correctness depending on the actions performed on the passed arguments. Adding a noexcept specifier resulted in a less elegant, longer, and less accessible implementation.

Is it worth the hassle? Jason Rice posted a comment on the previous article asking:

You know that you're obsessed with library design and abstractions when a simple for loop like this one...

for(int i = 0; i < 10; ++i)
{
foo();
}

...greatly bothers you.

What's wrong with it?