Hi Everyone, this is my first time floating an idea so apologies if I get the format wrong. Constructive criticism is very welcome!
I've had a look at the new std::optional<T> and as exciting as it is to finally have such a useful type in the standard, I worry that the feature may be too cumbersome and possibly too easy to use incorrectly. Here's an example of its current usage as provided by the C++ 17 standard:
// C++ 17 New Optional Usage //
if (auto customer = get_customer(customer_id)) {
process(*customer);
}
else {
show_customer_not_found();
}
This isn't too bad, but I think it could be better. The first issue I have is with `customer` being an actual std::optional instance. This creates a level of indirection that seems awkward to use. One must also remember to dereference the `customer` optional when attempting to gain access to the value as can be seen during the `process` call. It would be nice to remove this indirection and gain direct access to the underlying type rather than through the optional itself. After some thinking, I realized that the range-based for loop had the solution I was looking for. Essentially, an optional is a list containing either no items or exactly one item. In such a case, one could think of iterating over an optional as if it were a simple container:
// Example of an optional as if it were a container of one or zero items //
for (auto& customer : get_customer(customer_id)) {
process(customer);
}
Obviously, this syntax is a bit awkward. It just doesn't make sense to consider an optional as a container. Furthermore, there would likely be a high degree of unnecessary overhead in interpreting the optional as a container. Iterators would also have to be made to support the begin/end range. To correct these shortcomings, my proposal is to extend the range-based for loop syntax for single instance item which may or may not exist (optionals and pointers, primarily) to the `if` statement. Here is an example:
// New way with `if` auto-dereferencing language feature //
if (auto& customer : get_customer(customer_id)) {
process(customer); // customer is a Customer& and not an optional.
// We can safely use customer as we are guaranteed
// to have a valid reference and that reference
// cannot extend beyond the `if` scope
}
else {
show_customer_not_found();
}
As you can see, this feature is readable and addresses the indirection problem from earlier. Furthermore, it can be optimized easier for optional types and can theoretically work with any type, including user types, so long as they provide a conversion to boolean operator and a dereference operator. An example of how this could be interpreted follows:
// New feature translates into... //
auto _optional_customer = get_customer(customer_id);
if (_optional_customer) {
auto& customer = *_optional_customer;
process(customer);
}
else {
show_customer_not_found();
}
I'm sure language features are not the easiest thing to add, and I'm no compiler developer, but I'm anxious to hear any feedback you may have in regards to short comings, enhancements and overall complexity to implement. Thank you for considering this feature. - David Peterson