Boost logo

Boost :

Subject: [boost] [optional] operator<(optional<T>, T) -- is it wrong?
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2014-11-21 05:29:08


I moved this discussion from the other thread.

> optional<double> Aircraft::weight()
> {
> if (Impl* impl = get_impl())
> return impl->compute_weight();
> else
> return none;
> }
>
> double Aircraft::max_weight()
> {
> return 10000.0;
> }
>
> bool too_heavy(Aircraft& ac)
> {
> return ac.weight() > ac.max_weight();
> // this compiles and does the wrong thing
> }
>

1) When we are bringing T into the optional<T> land, we apply implicit
> constructor. For example, we provide T to a function taking optional<T>.
> Here, the direction of the conversion is unambiguous. Namely, T to
> optional<T>. So, we apply it.
>

2) When the direction of conversion is not as clear, we refuse applying it
> and leave it to the user. op<(T, optional<T>) would be one such example.
>

> Oh, c'mon. Cheer up. Things are not as gloomy, are they. :-) Here the
> subtlety (IMO) lies in how reasonable it is to add information. Namely, as
> I indicated, if we bring T into the optional<T> fold, then we apply
> optional<T> rules to T, i.e. apply t to optional<T> conversion. Say, we
> have a mandarin and an orange. When we bring the mandarin to an orange
> factory, then mandarin-to-orange "conversion" is applied and for all
> purposes mandarin is a "small orange". Outside the factory, when we compare
> mandarin to orange, it is not immediately clear what should be treated as
> what. If we apply mandarin-to-orange "conversion", then it'll be "small
> orange vs. big orange". If instead we apply orange-to-mandarin
> "conversion", then it'll be "sweet mandarin vs. sour mandarin". Given the
> library writer does not know, which it is, we ban it. Still not convinced?
> I've spent all munition I had. :-)

When you are talking about oranges and mandarins outside the context of
C++, I am convinced. the problem I have is with mapping it onto C++ and the
design of Optional.

(1) In C++ we have the converting constructor. This appears close to what
you call "bringing T into the optional<T> land", but I claim it is not the
same. And the consequences of these nuance differences result in the
problem in question. Perhaps the notion of "bringing T into the optional<T>
land" would be better reflected by an explicit constructor, or function
make_optional(). I am not saying that the converting constructor is wrong
here. I am just saying that the motivation is *slightly* different than
"bringing T into the optional<T> land", it is more for syntactic
convenience, which is almost the same, but not same.

(2) Your philosophy "when the direction of conversion is not as clear, we
refuse applying it" -- there is no way to apply it within the definition of
optional. We can apply it by poisoning every operation in the world that
takes T or optional<T>. But that looks impractical. Back to Vicente's
concern:

User defining its own function
>
> void f(optional<T>, optional<T>);
>
> would need to add the following?
>
> void f(T, optional<T>) { BOOST_STATIC_ASSERT(); }
> void f(optional<T>, T) { BOOST_STATIC_ASSERT(); }
>
> What if there are 3 optional parameters? We can not say to the user that
> they need to program this way.
>

I do not think it has been addressed.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk