Being lazy in C++
7 points by dalvrosa
7 points by dalvrosa
std::optional is not to blame for the behavior we started with
I want to blame std::optional anyway. I'm not part of the committee, I don't know what the thought process was, but I'm constantly trying to use C++20 features and then find incredibly basic functionality like std::optional::or_else didn't make the cut and had to wait until C++23. Was it just an issue of time constraints? Was there some sort of discourse not settled until the next revision? Did they just forget?
The normal use case for value_or is providing a default value for an empty optional, so I’ve never encountered this specific problem because the default value is normally free to compute.
That said, the general case of avoiding computing a value if it’s not needed is interesting and the lack limits the usability of some higher-level abstractions. For Verona, we considered a ‘lazy` qualifier on arguments that would turn the argument expression into a lambda that would evaluate to the argument. This is a fairly simple thing to add to C++, but it’s not clear what the scope should be. It would be trivial to have:
void foo([[lazy]] int x);
…
foo(expensive());
Transform to something semantically equivalent to:
std::optional<int> cache;
foo([&]() { if (!cache) { cache = expensive(); } return cache.value(); });
That’s something that’s trivial to describe as part of the language’s semantics. You could even require ‘operator()in the thunk to bevirtual` so that the callee doesn’t need compile-time specialisation.
But what happens if a temporary is used only in this lambda? What if the user instead writes:
int x = expensive();
foo(x);
Should it be a similar transform, or should only `x‘ be part of the lazy thunk? The former is what a lazy language such as Haskell does, the latter is easier to explain in a mostly eager language.
I’m tempted to write a paper proposing this at some point.
A lot of the time, it could be "they simply forget". Due to the nature of the C++ evolution process, the cost of "forgetting" a feature and adding it later could be 3 years (or even more), and it will also require another round of bikeshedding
I wish there was an option to provide an invocable type, it would be interesting to see if other languages try that method instead.