[optional] operator<(optional<T>, T) -- is it wrong?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
91 messages Options
12345
Reply | Threaded
Open this post in threaded view
|

[optional] operator<(optional<T>, T) -- is it wrong?

Andrzej Krzemienski
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.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Vladimir Batov-5

On 11/21/2014 09:29 PM, Andrzej Krzemienski wrote:
> ...

> (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.

They are obviously not the same -- "bringing" is an action, "converting
constructor" is the tool to execute that action... when needed. If we
have the tool (the constructor) it does not mean we swing it
indiscriminately and apply it everywhere it fits. There has to be
logical justification to apply that constructor... not just mechanical
ability to do that. The converter is a powerful tool. However, with that
"hammer" we should not fall into the trap of seeing everything like a nail.

> And the consequences of these nuance differences result in the problem
> in question.

To me the difference's not that "nuanced". "Action" and "tool" are like
"walking" and "shoes", "singing" and "microphone".

> Perhaps the notion of "bringing T into the optional<T> land" would be
> better reflected by an explicit constructor, or function make_optional().

Mechanically, yes. Logically I am sure there are places where the action
(of T to optional<T>) is unequivocal. If my API requests optional<T>,
then I explicitly say -- I deal with optional<T> and apply optional<T>
rules. I.e. my API is in the optional<T> land. So, when you provide T
instead, it's propagated to optional<T> at the point of entering my API.
The same as feed 'int' to func(double). It's not controversial, is it?
How func(optional<T>) is different?

> 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.

IMO no need complicating the matter with number of parameters. Just one
will do. Are you implying that for every

void f(optional<T>);

we need to have poisoned

void f(T) { BOOST_STATIC_ASSERT(); }

As I tried to describe above, if I specify "void f(optional<T>,
optional<T>);" as my API, then I explicitly say that it plays by
optional<T> rules. It's no different from "void f(double, double);"
called with "ints". If playing be optional<T> rules might be different
for T rules or potentially confusing, I suggest we poison it. op<(T,
optional<T>) is an excellent example because it implements interaction
of its two arguments and that interaction s different if

1) both args are T;
2) both args are optional<T>;
3) args are of different types.

As they are different, we should have 3 different implementations... #3
just happens to be no-implementation.

I might well fail to understand your concern as those examples above
seem far too hypothetical. If you can come up with a realistic example,
that'd probably help me to see what you see.

> I do not think it has been addressed.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Vladimir Batov
In reply to this post by Andrzej Krzemienski
Andrzej Krzemienski wrote
...
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.
The problem here (as I can see it) is that you supply an abstract fun(T, optional<T>) with no context whatsoever and then ask -- how it can be addressed -- promote T to optional<T> or poison... or something else?.. Obviously, no matter what the choice is it'll be correct for one set of real functions and wrong for others. So, the answer is "it depends on the context". Granted, it's very tempting to have one absolute truth, one simple answer to all fun(T, optional<T>) under the sun... Say, "shall not kill" sounds like a good rule to live by... unless one is attacked... then "kill in defence" might sound like a reasonable approach... unless one is at war... then "kill plenty" sounds like an expectation... I guess, all I am trying to convey with all that killing and mandarins and oranges is that we need to look at things in context and address those in context so that is, in the end, beneficial to the user.  From that perspective (usefulness, user-friendliness, rather than some hypothetical library purity) there cannot possibly be any doubts about sensible/unquestionable implicit promotion of T to optional<T>, about what is more natural, better for the user:

foo->set_time("11:55PM") or
foo->set_time(boost::optional<string>("11:55PM"))

As for op<(T, optional<T>), then the library writer'd like to be as helpful as possible and to provide as much functionality as possible. Unfortunately, there is just not enough context to go one way or the other. So, stating that by prohibiting the operator is the safest and most honest solution.





Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Andrzej Krzemienski
2014-11-24 7:42 GMT+01:00 Vladimir Batov <[hidden email]>:

> Andrzej Krzemienski wrote
> > ...
> > 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.
>
> The problem here (as I can see it) is that you supply an abstract fun(T,
> optional<T>) with no context whatsoever and then ask -- how it can be
> addressed -- promote T to optional<T> or poison... or something else?..
> Obviously, no matter what the choice is it'll be correct for one set of
> real
> functions and wrong for others. So, the answer is "it depends on the
> context". Granted, it's very tempting to have one absolute truth, one
> simple
> answer to all fun(T, optional<T>) under the sun... Say, "shall not kill"
> sounds like a good rule to live by... unless one is attacked... then "kill
> in defence" might sound like a reasonable approach... unless one is at
> war... then "kill plenty" sounds like an expectation... I guess, all I am
> trying to convey with all that killing and mandarins and oranges is that we
> need to look at things in context and address those in context so that is,
> in the end, beneficial to the user.  From that perspective (usefulness,
> user-friendliness, rather than some hypothetical library purity) there
> cannot possibly be any doubts about sensible/unquestionable implicit
> promotion of T to optional<T>, about what is more natural, better for the
> user:
>
> foo->set_time("11:55PM") or
> foo->set_time(boost::optional<string>("11:55PM"))
>
> As for op<(T, optional<T>), then the library writer'd like to be as helpful
> as possible and to provide as much functionality as possible.
> Unfortunately,
> there is just not enough context to go one way or the other. So, stating
> that by prohibiting the operator is the safest and most honest solution.
>

I think at this point I had better pause for some time and rethink, whether
it is just that I fail to deliver my point of view correctly, or whether I
am just too hang out to my own solution.

I get your arguments. It is just that they do not let me conclude that
op<(T, optional<T>) should be banned. Either I am too fixed on my point of
view, or there does exist an objective argument that I perceive, but cannot
put into words.

In general, my argument is not about being pure, but more about "can the
concept of optional<T> be easily explained and taught?". I sense that they
are different things, although I admit that when I try to explain it, the
explanations look the same in either case.

I will need to take some time and rethink.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Andrzej Krzemienski
2014-11-24 9:34 GMT+01:00 Andrzej Krzemienski <[hidden email]>:

>
>
> 2014-11-24 7:42 GMT+01:00 Vladimir Batov <[hidden email]>:
>
>> Andrzej Krzemienski wrote
>> > ...
>> > 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.
>>
>> The problem here (as I can see it) is that you supply an abstract fun(T,
>> optional<T>) with no context whatsoever and then ask -- how it can be
>> addressed -- promote T to optional<T> or poison... or something else?..
>> Obviously, no matter what the choice is it'll be correct for one set of
>> real
>> functions and wrong for others. So, the answer is "it depends on the
>> context". Granted, it's very tempting to have one absolute truth, one
>> simple
>> answer to all fun(T, optional<T>) under the sun... Say, "shall not kill"
>> sounds like a good rule to live by... unless one is attacked... then "kill
>> in defence" might sound like a reasonable approach... unless one is at
>> war... then "kill plenty" sounds like an expectation... I guess, all I am
>> trying to convey with all that killing and mandarins and oranges is that
>> we
>> need to look at things in context and address those in context so that is,
>> in the end, beneficial to the user.  From that perspective (usefulness,
>> user-friendliness, rather than some hypothetical library purity) there
>> cannot possibly be any doubts about sensible/unquestionable implicit
>> promotion of T to optional<T>, about what is more natural, better for the
>> user:
>>
>> foo->set_time("11:55PM") or
>> foo->set_time(boost::optional<string>("11:55PM"))
>>
>> As for op<(T, optional<T>), then the library writer'd like to be as
>> helpful
>> as possible and to provide as much functionality as possible.
>> Unfortunately,
>> there is just not enough context to go one way or the other. So, stating
>> that by prohibiting the operator is the safest and most honest solution.
>>
>
> I think at this point I had better pause for some time and rethink,
> whether it is just that I fail to deliver my point of view correctly, or
> whether I am just too hang out to my own solution.
>
> I get your arguments. It is just that they do not let me conclude that
> op<(T, optional<T>) should be banned. Either I am too fixed on my point of
> view, or there does exist an objective argument that I perceive, but cannot
> put into words.
>
> In general, my argument is not about being pure, but more about "can the
> concept of optional<T> be easily explained and taught?". I sense that they
> are different things, although I admit that when I try to explain it, the
> explanations look the same in either case.
>
> I will need to take some time and rethink.
>

Anyone else? Would you be affected if  operator<(optional<T>, T) is
poisoned?
(but operator==(optional<T>, T) remains working)

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Marcel Raad
Andrzej Krzemienski <akrzemi1 <at> gmail.com> writes:

> Anyone else? Would you be affected if  operator<(optional<T>, T) is
> poisoned?
> (but operator==(optional<T>, T) remains working)

I actually had a small bug in production code a few years ago after
changing an integral type to an optional because I hadn't expected this
behavior, so I think that would be good.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Vladimir Batov-5
In reply to this post by Andrzej Krzemienski
On 11/24/2014 09:07 PM, Andrzej Krzemienski wrote:
> Anyone else? Would you be affected if operator<(optional<T>, T) is
> poisoned? (but operator==(optional<T>, T) remains working)

Another *pragmatic* point (probably more relevant for the std::optional
variant) is if op<(T, optional<T>) is prohibited now and then later it
is decided that decision was wrong (even though I can't possibly see how
as it does not take *any* functionality away), then adding it back will
not cause any issues. On the contrary, it op<() is allowed to stay now
and later it's decided that decision was wrong and op<() is better taken
out, then it won't be possible to do... well, much harder anyway as it's
be a breaking change.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Vicente Botet
Le 25/11/14 21:13, Vladimir Batov a écrit :

> On 11/24/2014 09:07 PM, Andrzej Krzemienski wrote:
>> Anyone else? Would you be affected if operator<(optional<T>, T) is
>> poisoned? (but operator==(optional<T>, T) remains working)
>
> Another *pragmatic* point (probably more relevant for the
> std::optional variant) is if op<(T, optional<T>) is prohibited now and
> then later it is decided that decision was wrong (even though I can't
> possibly see how as it does not take *any* functionality away), then
> adding it back will not cause any issues. On the contrary, it op<() is
> allowed to stay now and later it's decided that decision was wrong and
> op<() is better taken out, then it won't be possible to do... well,
> much harder anyway as it's be a breaking change.
>
>
Following your reasoning, I will suggest to remove the implicit
construction from T to optional<T> and/or remove the
operator<(optional<T>, optional<>). If we can not live without them, we
could always try to do whatever is better.

Best,
Vicente



_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Edward Diener-3
On 11/25/2014 7:18 PM, Vicente J. Botet Escriba wrote:

> Le 25/11/14 21:13, Vladimir Batov a écrit :
>> On 11/24/2014 09:07 PM, Andrzej Krzemienski wrote:
>>> Anyone else? Would you be affected if operator<(optional<T>, T) is
>>> poisoned? (but operator==(optional<T>, T) remains working)
>>
>> Another *pragmatic* point (probably more relevant for the
>> std::optional variant) is if op<(T, optional<T>) is prohibited now and
>> then later it is decided that decision was wrong (even though I can't
>> possibly see how as it does not take *any* functionality away), then
>> adding it back will not cause any issues. On the contrary, it op<() is
>> allowed to stay now and later it's decided that decision was wrong and
>> op<() is better taken out, then it won't be possible to do... well,
>> much harder anyway as it's be a breaking change.
>>
>>
> Following your reasoning, I will suggest to remove the implicit
> construction from T to optional<T> and/or remove the
> operator<(optional<T>, optional<>). If we can not live without them, we
> could always try to do whatever is better.

I do not understand why anyone feels that the less than operator for
boost::optional<T> is wrong.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Matt Calabrese
On Tue, Nov 25, 2014 at 5:27 PM, Edward Diener <[hidden email]>
wrote:

> On 11/25/2014 7:18 PM, Vicente J. Botet Escriba wrote:
>>
>> Following your reasoning, I will suggest to remove the implicit
>> construction from T to optional<T> and/or remove the
>> operator<(optional<T>, optional<>). If we can not live without them, we
>> could always try to do whatever is better.
>>
>
> I do not understand why anyone feels that the less than operator for
> boost::optional<T> is wrong.


I can MAYBE see not having them as long as std::less and family are still
specialized accordingly (specializing std::less is [correctly, IMO] in for
the proposed standard optional now anyway, thanks to Tony Van Eerd).
Ultimately, though, I really don't think there's a problem with also having
the operators overloaded. I simply don't buy the "gotchas."


--
-Matt Calabrese

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Edward Diener-3
On 11/25/2014 10:20 PM, Matt Calabrese wrote:

> On Tue, Nov 25, 2014 at 5:27 PM, Edward Diener <[hidden email]>
> wrote:
>
>> On 11/25/2014 7:18 PM, Vicente J. Botet Escriba wrote:
>>>
>>> Following your reasoning, I will suggest to remove the implicit
>>> construction from T to optional<T> and/or remove the
>>> operator<(optional<T>, optional<>). If we can not live without them, we
>>> could always try to do whatever is better.
>>>
>>
>> I do not understand why anyone feels that the less than operator for
>> boost::optional<T> is wrong.
>
>
> I can MAYBE see not having them as long as std::less and family are still
> specialized accordingly (specializing std::less is [correctly, IMO] in for
> the proposed standard optional now anyway, thanks to Tony Van Eerd).
> Ultimately, though, I really don't think there's a problem with also having
> the operators overloaded. I simply don't buy the "gotchas."

If the C++ standard says that associative container of std::optionals is
fine but some programmers believe that manually comparing them via the
less than operator is not fine, I think we have a real conceptual
problem here, even outside of the mere non-orthogonality of the situation.





_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Vladimir Batov-5

On 11/26/2014 02:33 PM, Edward Diener wrote:

> On 11/25/2014 10:20 PM, Matt Calabrese wrote:
>> On Tue, Nov 25, 2014 at 5:27 PM, Edward Diener <[hidden email]>
>> wrote:
>>
>>> On 11/25/2014 7:18 PM, Vicente J. Botet Escriba wrote:
>>>>
>>>> Following your reasoning, I will suggest to remove the implicit
>>>> construction from T to optional<T> and/or remove the
>>>> operator<(optional<T>, optional<>). If we can not live without
>>>> them, we
>>>> could always try to do whatever is better.
>>>>
>>>
>>> I do not understand why anyone feels that the less than operator for
>>> boost::optional<T> is wrong.
>>
>>
>> I can MAYBE see not having them as long as std::less and family are
>> still
>> specialized accordingly (specializing std::less is [correctly, IMO]
>> in for
>> the proposed standard optional now anyway, thanks to Tony Van Eerd).
>> Ultimately, though, I really don't think there's a problem with also
>> having
>> the operators overloaded. I simply don't buy the "gotchas."
>
> If the C++ standard says that associative container of std::optionals
> is fine but some programmers believe that manually comparing them via
> the less than operator is not fine, I think we have a real conceptual
> problem here, even outside of the mere non-orthogonality of the
> situation.

The discussion is not about

     op<(optional<T>, optional<T>)

but rather

     op<(T, optional<T>)

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Matt Calabrese
In reply to this post by Edward Diener-3
On Tue, Nov 25, 2014 at 7:33 PM, Edward Diener <[hidden email]>
wrote:
>
> If the C++ standard says that associative container of std::optionals is
> fine but some programmers believe that manually comparing them via the less
> than operator is not fine, I think we have a real conceptual problem here,
> even outside of the mere non-orthogonality of the situation.
>

We already have this kind of thing in the standard. Consider pointer types.
You can use std::less with arbitrary pointers, but this is not the case
with operator< (though operator< is well defined when the objects pointed
to are in the same array).

Again, I'm not advocating leaving out operator< for optional, but if the
main reason why people want it is because it makes it easy to work with
associative containers, we already have precedent in the standard to allow
this and not operator<.

--
-Matt Calabrese

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Vladimir Batov
In reply to this post by Vicente Botet
Vicente Botet wrote
...
Following your reasoning, I will suggest to remove the implicit
construction from T to optional<T> and/or remove the
operator<(optional<T>, optional<>). If we can not live without them, we
could always try to do whatever is better.
Vicente, you are not serious, right?.. It is just that you did not like/agree with my "reasoning" and, so you suggested something unreasonable (IMO) and presented it as a "consequence" of my "reasoning" just to indicate how ridiculous mine was... Was that the idea?... Or I am misunderstanding you post?

I cannot live without implicit T to optional<T> and prohibiting it will break tonnes of my code and project code and Fernando Cacciola's code (if I remember our similar discussions years ago)... and it'll break all that code *now*... no need to wait and see... and "selling" optional<T> without implicit T to optional<T> will be real hard... in my neck of the woods anyway.

Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Vicente Botet
Le 26/11/14 06:26, Vladimir Batov a écrit :

> Vicente Botet wrote
>> ...
>> Following your reasoning, I will suggest to remove the implicit
>> construction from T to optional
>> <T>
>>   and/or remove the
>> operator<(optional
>> <T>
>> , optional<>). If we can not live without them, we
>> could always try to do whatever is better.
> Vicente, you are not serious, right?.. It is just that you did not
> like/agree with my "reasoning" and, so you suggested something unreasonable
> (IMO) and presented it as a "consequence" of my "reasoning" just to indicate
> how ridiculous mine was... Was that the idea?... Or I am misunderstanding
> you post?
Vladimir, yes and not. Were talking of the possibility of a new
safe_optional. I would like we explore how we would like to have this
new type.
> I cannot live without implicit T to optional<T> and prohibiting it will
> break tonnes of my code and project code and Fernando Cacciola's code (if I
> remember our similar discussions years ago)... and it'll break all that code
> *now*... no need to wait and see... and "selling" optional<T> without
> implicit T to optional<T> will be real hard... in my neck of the woods
> anyway.
>
>
>
I understand your backward compatibility concern? I'm not suggesting at
all to change boost::optional.
I'm looking on how all these conversions can be made safer.

You surely remember my Boost.Conversion proposal that was rejected. I
believe that there is something interesting behind this idea.
The idea is to state explicitly that you want a explicit conversion but
don't state to what. The what is deduced from the context.
Boost.Conversion was a library proposal. We could rethink it as a
language proposal. Let me represent by

[ x ]

this explicit conversion to the context.
With this we could be able to

   optional<int> f(int x) {
     if (x<0)
         return nullopt ;
     }
     return [ x ];
    }

[ x ] is longer than x but shorter than make_optional(x).

The meaning of

    return [ x ]

on the context of a function returning M would be given by

   return M(x);

We could also add an indirection and translate it to

   return make_explicitly(type<M>{}, x);

or

   return type<M>{}[x];

where the type<M> instance is used only to be able to overload on M.

    template <class T>
    struct type {};

The default implementation could then be a call to the explicit
constructor of the context from the parameter

   // default to explicit constructor
   template <class M, class X>
   M make_explicitly(type<M>, X && x) { return M(std::forward<T>(x)); }

We could stop here or we could use [ x ] not only on a return statement
but also in any expression as in

    optional<int> oi;
    int x;
    ...
    if ( oi < [x] )
       ....

Note that we don't need an implicit conversion from T to optional<T>
then but only an explicit one, avoiding the more verbose

   if ( oi < std::make_optional(x) )

This can be applied also on the context of the await proposal to
separate the concerns. await will take care of the the continuation part
and {{}} will take care explicit conversion transformation.


future<int> f(int x) {
   if (x > 10)
     return await something_long(x);
   else
     return [ x + 1 ]; // make_ready_future
}

This operator could be used also to mean the empty set, as in

set<int> f {

   ...
   return [];
};

Another example

variant< int, string> f(int x) {
   if (x > 10)
     return [ std::string("___") ];
    else
     return [ x + 1 ];
}

Indirectly Herb Sutter proposal [n4074] "Let return {expr} Be Explicit"
and Gor Nishanov  [4134] Resumable functions proposal interact with this
implicit explicit conversion thing.

I don't know how to implement in C++14 the mreturn Haskell

Monad m =>mreturn :: a -> m a

as C++14 doesn't consider the context of the call and so the m can not
be deduced.


I hope it is clear now that I don't want to change optional but see what
the safer optional could be with the ongoing C++ proposals.

Best,
Vicente



_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Felix Uhl
In reply to this post by Andrzej Krzemienski
Vincente J. Botet Escriba wrote:

>I hope it is clear now that I don't want to change optional but see what
>the safer optional could be with the ongoing C++ proposals.


Fair enough, different users want different behaviour,

but how is optional not safe in any way?


operator<(optional<T>, T) does not throwing any kinds of exceptions

when operator<(T,T) doesn’t, does it?




---

Felix Uhl

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Rob Stewart-6
In reply to this post by Vicente Botet
On November 26, 2014 2:12:56 AM EST, "Vicente J. Botet Escriba" <[hidden email]> wrote:

>Le 26/11/14 06:26, Vladimir Batov a écrit :
>> Vicente Botet wrote
>>> ...
>>> Following your reasoning, I will suggest to remove the implicit
>>> construction from T to optional
>>> <T>
>>>   and/or remove the
>>> operator<(optional
>>> <T>
>>> , optional<>).
>>
>> Vicente, you are not serious, right?..
>
>Vladimir, yes and not. Were talking of the possibility of a new
>safe_optional. I would like we explore how we would like to have this
>new type.

[snip]

>I'm looking on how all these conversions can be made safer.

[snip]

>The idea is to state explicitly that you want a explicit conversion but
>don't state to what. The what is deduced from the context.

That idea is rather odd to me. One is hardly being explicit if one is relying on context to determine the target type.

>Let me represent by
>
>[ x ]
>
>this explicit conversion to the context.
>With this we could be able to
>
>   optional<int> f(int x) {
>     if (x<0)
>         return nullopt ;
>     }
>     return [ x ];
>    }
>
>[ x ] is longer than x but shorter than make_optional(x).
>
>The meaning of
>
>    return [ x ]

The target type is reasonably deduced to be the function return type, so this is a means to avoid repeating the type. auto would work as well: return auto(x);. That's on keeping with auto's purpose.

>on the context of a function returning M would be given by
>
>   return M(x);
>
>We could also add an indirection and translate it to
>
>   return make_explicitly(type<M>{}, x);
>
>or
>
>   return type<M>{}[x];
>
>where the type<M> instance is used only to be able to overload on M.
>
>    template <class T>
>    struct type {};
>
>The default implementation could then be a call to the explicit
>constructor of the context from the parameter
>
>   // default to explicit constructor
>   template <class M, class X>
>   M make_explicitly(type<M>, X && x) { return M(std::forward<T>(x)); }

Using auto would be simpler.

>We could stop here or we could use [ x ] not only on a return statement
>
>but also in any expression as in
>
>    optional<int> oi;
>    int x;
>    ...
>    if ( oi < [x] )
>       ....
>
>Note that we don't need an implicit conversion from T to optional<T>
>then but only an explicit one, avoiding the more verbose
>
>   if ( oi < std::make_optional(x) )

If anything in the expression or calling context changes, the target type can change. How is that explicit? It's no better than an implicit conversion. Indeed, it's worse: it bypasses the control implied by marking a constructor explicit.

>This can be applied also on the context of the await proposal to
>separate the concerns. await will take care of the the continuation
>part
>and {{}} will take care explicit conversion transformation.
>
>future<int> f(int x) {
>   if (x > 10)
>     return await something_long(x);
>   else
>     return [ x + 1 ]; // make_ready_future
>}

Use auto for the return statement.

>This operator could be used also to mean the empty set, as in
>
>set<int> f {
>
>   ...
>   return [];
>};

This is just default construction. How about auto() or auto{}?

>Another example
>
>variant< int, string> f(int x) {
>   if (x > 10)
>     return [ std::string("___") ];
>    else
>     return [ x + 1 ];
>}

These are return statements, so just use auto here, too.

___
Rob

(Sent from my portable computation engine)

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Vladimir Batov
In reply to this post by Vicente Botet
Vicente Botet wrote
... Were talking of the possibility of a new
safe_optional. I would like we explore how we would like to have this
new type.
I am not against any new types which prove to be useful... just do not call it *_optional. Let your class stand on its own feet and be judged on its own merit... instead of piggy-backing on "optional"... and confusing and fragmenting "optional" user-base.  

... I'm looking on how all these conversions can be made safer.
...
OK, Vicente, my most humble apologies for snipping all the stuff you typed that flew right over my head and made me feel stupid. I have to be brutally honest I did not understand your "idea to state explicitly that you want a explicit conversion but don't state to what" and your "implicit explicit conversion thing". You obviously put a lot of thought into it but I personally did not get *what problem* exactly you are trying to solve. I personally do not feel there is a conversion-related problem that needs fixing... On the other hand I do not know Haskell, so it may well be that I do not know what I am missing. :-) I just hope that other people you'll present your idea to will be smarter than me to appreciate it. Do you have any links to slow-pace tutorial/explanation/justification of what you are trying to propose that I could peruse without hurry?

Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

David Stone
In reply to this post by Andrzej Krzemienski
I have been bitten in the past by operator<. I was converting code that
used unsigned with a 'magic value' to represent nullness to
boost::optional<std::uint32_t>. However, the maximum value it used was
std::numeric_limits<std::uint32_t>:max(). A simple find and replace for
this magic constant (which was referred to everywhere as DWORD_NULL) with
boost::none and fixing compile errors led to some erroneous code. We had
code that assumed an 'uninitialized' std::uint32_t was greater than any
valid value.

The concept of "value not present" is not inherently less-than or
greater-than any value, but because of operator<, code compiled that
shouldn't have. I suppose this is really an argument against any operator<
overload, not just the mixed-type comparison. I don't expect this to be a
major problem for new code, but there is a lot of code out there that uses
a magic value, and that is what optional is supposed to replace.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [optional] operator<(optional<T>, T) -- is it wrong?

Edward Diener-3
In reply to this post by Vladimir Batov-5
On 11/25/2014 10:44 PM, Vladimir Batov wrote:

>
> On 11/26/2014 02:33 PM, Edward Diener wrote:
>> On 11/25/2014 10:20 PM, Matt Calabrese wrote:
>>> On Tue, Nov 25, 2014 at 5:27 PM, Edward Diener <[hidden email]>
>>> wrote:
>>>
>>>> On 11/25/2014 7:18 PM, Vicente J. Botet Escriba wrote:
>>>>>
>>>>> Following your reasoning, I will suggest to remove the implicit
>>>>> construction from T to optional<T> and/or remove the
>>>>> operator<(optional<T>, optional<>). If we can not live without
>>>>> them, we
>>>>> could always try to do whatever is better.
>>>>>
>>>>
>>>> I do not understand why anyone feels that the less than operator for
>>>> boost::optional<T> is wrong.
>>>
>>>
>>> I can MAYBE see not having them as long as std::less and family are
>>> still
>>> specialized accordingly (specializing std::less is [correctly, IMO]
>>> in for
>>> the proposed standard optional now anyway, thanks to Tony Van Eerd).
>>> Ultimately, though, I really don't think there's a problem with also
>>> having
>>> the operators overloaded. I simply don't buy the "gotchas."
>>
>> If the C++ standard says that associative container of std::optionals
>> is fine but some programmers believe that manually comparing them via
>> the less than operator is not fine, I think we have a real conceptual
>> problem here, even outside of the mere non-orthogonality of the
>> situation.
>
> The discussion is not about
>
>      op<(optional<T>, optional<T>)
>
> but rather
>
>      op<(T, optional<T>)

You have types A, B. There is an implicit conversion from A to B.

op<(A,A) is defined.
op<(B,B) is defined.

but you object if

op<(A,B) or op<(B,A) is defined.

I am sorry but this is too clever for me and I do not get the point. If
it is purely to protect the programmer from his own error in not
understanding the relation between A and B I do not agree with this.
There must be a strong, other valid reason. If in this particular case
you document the ordering of values in A and B there is no strong case
that I can see. Misuse of a class by a programmer too lazy or unaware to
understand how it works is not a valid reason to remove functionality
for everybody else. If you want coddling, use some other language ( like
Java for instance ). In C++ we either know what we are doing or we don't
use what we don't know. It is the same whether it is the language or a
library.

I am certainly not against an alternative class related to optional if
that is what others want to develop. But please don't call it
'safe_optional'. And leave optional itself alone in this respect. It is
fine the way it is for me.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
12345