Date: Mon, 2 Aug 2021 10:18:00 -0500
On Mon, Aug 2, 2021 at 10:01 AM Jason McKesson via Std-Proposals <
std-proposals_at_[hidden]> wrote:
>
> I think that's the core of the problem here: the "right semantic" for
> references is *not* the "right semantic" for *values*. It makes
> absolutely no sense for assignment to an optional value type to
> unengage/re-engage. Values are values, and if a value is assignable,
> then assigning to it has a clear and unambiguous meaning.
>
optional<T&> simply treats T& as a *value *rather than a *reference*. Once
you accept that, you'll see that it's the same semantic.
>
> If you want to have `optional<T&>`'s assignment behave this way, then
> it's clear that it cannot be *spelled* `optional<T&>`. This is for the
> same reason that `vector<bool>`s mistake is that it's called "vector".
> `vector`'s are supposed to have specific behavior, and `vector<bool>`
> doesn't follow that. Same goes for `optional<T>`: it has specific,
> reasonable behavior which `optional<T&>` wouldn't have.
>
The comparison to vector<bool> fails really badly. vector<bool> differs
from vector<T> in basically all respects - every function has different
semantics, vector<bool> isn't a range of bool, it's not contiguous,
basically everything does something different.
optional<T&>, on the other hand, has the same behavior as optional<T> in
all cases - once you accept that it treats T& as a value. It simply does
not have differing semantics, unlike vector<bool>. Generic code on
optional<U> does actually work for U being a reference or not - because the
semantics are the same.
And it bears repeating that there is a lot of implementation experience
with a rebinding optional reference, with no corresponding
vector<bool>-like regret, while there is zero implementation experience
with an assign-through optional reference.
>
> If you believe that this is the right semantic for references, then it
> needs to be a separate class from optional values.
>
Consider this. Does an int[10] have different range semantics from
std::array<int, 10>? Your argument here is that it does - the latter calls
member begin() and end() while the former does something *completely
different* and so if we want to treat int[10] and array<int, 10> the same
then we should have different named range-based-for loops to iterate over
both.
But they're not different. The fact that we have different *syntax* to
iterate over a C array vs a std::array does not mean that that iteration
has different semantics, and we just hide that difference in the language
and the library. Likewise, the fact that we have different *syntax* to
change the value of an optional<T&> does not mean that it has different
*semantics* from any other optional<T>. The semantics of p = q are that we
change the value of p to be the value of q. Rebinding optional<T&> does
that.
Barry
std-proposals_at_[hidden]> wrote:
>
> I think that's the core of the problem here: the "right semantic" for
> references is *not* the "right semantic" for *values*. It makes
> absolutely no sense for assignment to an optional value type to
> unengage/re-engage. Values are values, and if a value is assignable,
> then assigning to it has a clear and unambiguous meaning.
>
optional<T&> simply treats T& as a *value *rather than a *reference*. Once
you accept that, you'll see that it's the same semantic.
>
> If you want to have `optional<T&>`'s assignment behave this way, then
> it's clear that it cannot be *spelled* `optional<T&>`. This is for the
> same reason that `vector<bool>`s mistake is that it's called "vector".
> `vector`'s are supposed to have specific behavior, and `vector<bool>`
> doesn't follow that. Same goes for `optional<T>`: it has specific,
> reasonable behavior which `optional<T&>` wouldn't have.
>
The comparison to vector<bool> fails really badly. vector<bool> differs
from vector<T> in basically all respects - every function has different
semantics, vector<bool> isn't a range of bool, it's not contiguous,
basically everything does something different.
optional<T&>, on the other hand, has the same behavior as optional<T> in
all cases - once you accept that it treats T& as a value. It simply does
not have differing semantics, unlike vector<bool>. Generic code on
optional<U> does actually work for U being a reference or not - because the
semantics are the same.
And it bears repeating that there is a lot of implementation experience
with a rebinding optional reference, with no corresponding
vector<bool>-like regret, while there is zero implementation experience
with an assign-through optional reference.
>
> If you believe that this is the right semantic for references, then it
> needs to be a separate class from optional values.
>
Consider this. Does an int[10] have different range semantics from
std::array<int, 10>? Your argument here is that it does - the latter calls
member begin() and end() while the former does something *completely
different* and so if we want to treat int[10] and array<int, 10> the same
then we should have different named range-based-for loops to iterate over
both.
But they're not different. The fact that we have different *syntax* to
iterate over a C array vs a std::array does not mean that that iteration
has different semantics, and we just hide that difference in the language
and the library. Likewise, the fact that we have different *syntax* to
change the value of an optional<T&> does not mean that it has different
*semantics* from any other optional<T>. The semantics of p = q are that we
change the value of p to be the value of q. Rebinding optional<T&> does
that.
Barry
Received on 2021-08-02 10:18:16