[optional] Safe optional

classic Classic list List threaded Threaded
87 messages Options
12345
Reply | Threaded
Open this post in threaded view
|

[optional] Safe optional

Andrzej Krzemienski
Hi Everyone,
I would like to run an idea through everyone in this list. There is a
recurring complaint about Boost.Optional that it allows you to do "unsafe"
things:
1. Inadvertent mixed comparisons between T and optional<T>
2. Unintended conversion from T to optional<T>
3. "Unchecked" access to the contained object, which causes an UB when
performed on an uninitialized optional object.

There are valid reasons why optional is defined the way it is defined. But
at the same time the complaints above are also valid. This makes some
people abandon Boost.Optional and use their own alternative.

My idea is to provide another type wrapper, say safe_optional<T>, that
would choose different tradeoffs: prefer "safety" to some flexibility
and/or efficiency. It would probably be part of Boost.Optional library as
the implementation can be reused - only the interface would be changed.

One downside of this solution is that we would have two libraries for doing
nearly the same thing, which could "scatter" the community. There is a
value for standardizing certain things and making them universal.

I would like to solicit your feedback.

Regards,
&rzej

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

Re: [optional] Safe optional

Mostafa-6
On Sun, 16 Nov 2014 23:04:43 -0800, Andrzej Krzemienski  
<[hidden email]> wrote:

> Hi Everyone,
> I would like to run an idea through everyone in this list. There is a
> recurring complaint about Boost.Optional that it allows you to do  
> "unsafe"
> things:
> 1. Inadvertent mixed comparisons between T and optional<T>
> 2. Unintended conversion from T to optional<T>
> 3. "Unchecked" access to the contained object, which causes an UB when
> performed on an uninitialized optional object.

Number 3 is really not an issue IMO. If you're going to overload operator*  
then existing C++ practice dictates that you have to do if(opt) before  
dereferencing opt, otherwise you'll have UB.


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

Re: [optional] Safe optional

Matt Calabrese
In reply to this post by Andrzej Krzemienski
On Sun, Nov 16, 2014 at 11:04 PM, Andrzej Krzemienski <[hidden email]>
wrote:

> Hi Everyone,
> I would like to run an idea through everyone in this list. There is a
> recurring complaint about Boost.Optional that it allows you to do "unsafe"
> things:
> 1. Inadvertent mixed comparisons between T and optional<T>
> 2. Unintended conversion from T to optional<T>
> 3. "Unchecked" access to the contained object, which causes an UB when
> performed on an uninitialized optional object.
>
> There are valid reasons why optional is defined the way it is defined. But
> at the same time the complaints above are also valid. This makes some
> people abandon Boost.Optional and use their own alternative.
>

I don't immediately see the problem with the mixed comparisons between T
and optional T... except maybe confusion regarding optional<bool> or
bool-like types. Is this what you're referring to? If so, then I sort of
disagree that it's a legitimate problem. If you are not talking about
issues relating to bool or have some really compelling optional<bool>
cases, can you point me to examples as to why this is suggested to be
unsafe. I don't really care that much about the mixed comparisons, but I
consider them pretty benign and if people find it useful then I won't
remove it unless the current uses are fully considered.

As for #2, I think I agree that conversion should probably be more explicit
and is potentially a step in a positive direction.

As for #3, if you are implying the alternative is to throw an exception,
then I'd say that's a flat-out no. That's a logic error and we shouldn't
throw an exception. The only thing that comes of that is people using the
exception for basic control flow -- if they knew the optional didn't point
to anything, then they wouldn't be dereferencing it. If they THOUGHT the
optional pointed to something and it didn't, then they have a bug, which
means the way to "handle" it is to fix the code. If they don't know at the
time of the access whether there was something there or not, then they
shouldn't deference it, using an exception for control flow. In that last
case, they should either be explicitly branching or they should use some
kind of visitation. If you're not talking about exceptions, then what
exactly are you proposing?

Regardless, if people come to an agreement on changes, I'm much more in
favor of simply making breaking changes to the current optional rather than
introducing another one. It's unfortunate for a type as fundamental and
widely used as optional, but people will get over it, especially if it
makes it closer to the standard proposal.

--
-Matt Calabrese

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

Re: [optional] Safe optional

Andrzej Krzemienski
2014-11-17 9:40 GMT+01:00 Matt Calabrese <[hidden email]>:

> On Sun, Nov 16, 2014 at 11:04 PM, Andrzej Krzemienski <[hidden email]>
> wrote:
>
> > Hi Everyone,
> > I would like to run an idea through everyone in this list. There is a
> > recurring complaint about Boost.Optional that it allows you to do
> "unsafe"
> > things:
> > 1. Inadvertent mixed comparisons between T and optional<T>
> > 2. Unintended conversion from T to optional<T>
> > 3. "Unchecked" access to the contained object, which causes an UB when
> > performed on an uninitialized optional object.
> >
> > There are valid reasons why optional is defined the way it is defined.
> But
> > at the same time the complaints above are also valid. This makes some
> > people abandon Boost.Optional and use their own alternative.
> >
>
> I don't immediately see the problem with the mixed comparisons between T
> and optional T... except maybe confusion regarding optional<bool> or
> bool-like types. Is this what you're referring to? If so, then I sort of
> disagree that it's a legitimate problem. If you are not talking about
> issues relating to bool or have some really compelling optional<bool>
> cases, can you point me to examples as to why this is suggested to be
> unsafe. I don't really care that much about the mixed comparisons, but I
> consider them pretty benign and if people find it useful then I won't
> remove it unless the current uses are fully considered.
>
> As for #2, I think I agree that conversion should probably be more explicit
> and is potentially a step in a positive direction.
>
> As for #3, if you are implying the alternative is to throw an exception,
> then I'd say that's a flat-out no. That's a logic error and we shouldn't
> throw an exception. The only thing that comes of that is people using the
> exception for basic control flow -- if they knew the optional didn't point
> to anything, then they wouldn't be dereferencing it. If they THOUGHT the
> optional pointed to something and it didn't, then they have a bug, which
> means the way to "handle" it is to fix the code. If they don't know at the
> time of the access whether there was something there or not, then they
> shouldn't deference it, using an exception for control flow. In that last
> case, they should either be explicitly branching or they should use some
> kind of visitation. If you're not talking about exceptions, then what
> exactly are you proposing?
>

No, no exceptions.
The solution is based on the observation that there is a limited number of
things you can do with optional<T>

optional<int> oi = ...;

1:
if (oi) doSomething(*oi);
else doSomethingElse(); // or nothing

2:
if (oi) doSomething(*oi);
else doSomething(-1); // use default value

3:
if (!oi) oi = (int)getIntByOtherMeans();
doSomething(*oi); // now it is safe

Now we simply provide a dedicated interface for each of these three usages:

1:
oi.use(&doSomething, &doSomethingElse); // or use lambdas

2:
doSomething(oi.value_or(-1));

3:
doSomething(oi.value_or_eval(getIntByOtherMeans));


> Regardless, if people come to an agreement on changes, I'm much more in
> favor of simply making breaking changes to the current optional rather than
> introducing another one. It's unfortunate for a type as fundamental and
> widely used as optional, but people will get over it, especially if it
> makes it closer to the standard proposal.
>

I would rather not go that way. boost::optional is not unsafe. It is simply
something else than what some people think. Its conceptual model is more
like any value of T, plus one additional value. In this model implicit
conversions make perfect sense and are n fact desirable.

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

Re: [optional] Safe optional

Mostafa-6
In reply to this post by Andrzej Krzemienski
On Sun, 16 Nov 2014 23:04:43 -0800, Andrzej Krzemienski  
<[hidden email]> wrote:

> Hi Everyone,
> I would like to run an idea through everyone in this list. There is a
> recurring complaint about Boost.Optional that it allows you to do  
> "unsafe"
> things:
> 1. Inadvertent mixed comparisons between T and optional<T>
> 2. Unintended conversion from T to optional<T>

The problem with optional is that it tries to be a drop-in replacement  
proxy for its underlying type, and, unfortunately, it can't fully do that.  
So it ends up with an identity crisis. IMO, optional should be treated as  
a first class object, not a thin wrapper around T, that means no implicit  
conversions to/from T, no implicit comparisons with T, etc... Last time I  
looked at this, that will solve the reference rebinding gotcha. That is,  
you'll have one behavior for optional<T> and optional<T&>. It will also  
solve the following gotcha too:

   optional<bool> b(false);

   if(b == true)
   {
      // Does not get executed.
      std::cout << "???\n";
   }

   if(b)
   {
     // Gets executed.
     std::cout << "!!!\n";
   }

which I believe to be an ever bigger problem.

In short, and IMHO optional should be a true model of the pointer concept,  
like iterators and shared_ptr.


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

Re: [optional] Safe optional

Matt Calabrese
In reply to this post by Andrzej Krzemienski
On Nov 17, 2014 1:25 AM, "Andrzej Krzemienski" <[hidden email]> wrote:

> No, no exceptions.
> The solution is based on the observation that there is a limited number of
> things you can do with optional<T>
>
> optional<int> oi = ...;
>
> 1:
> if (oi) doSomething(*oi);
> else doSomethingElse(); // or nothing
>
> 2:
> if (oi) doSomething(*oi);
> else doSomething(-1); // use default value
>
> 3:
> if (!oi) oi = (int)getIntByOtherMeans();
> doSomething(*oi); // now it is safe
>
> Now we simply provide a dedicated interface for each of these three
usages:
>
> 1:
> oi.use(&doSomething, &doSomethingElse); // or use lambdas
>
> 2:
> doSomething(oi.value_or(-1));
>
> 3:
> doSomething(oi.value_or_eval(getIntByOtherMeans));

While I agree that we should be encouraging high order functions/visitation
here, my personal experience is simply that many people do not like it.
When given the choice to pass a lamda or to use an "if" or a
range-based-for over high order function alternatives, programmers will
generally opt for not using a lambda. The fact that Bjarne thinks
visitation is somehow "bad" doesn't help. I agree that it's safer and I'd
be in favor of it, but be aware that not everyone will like it.

That said, I'd be in favor of this. If going with this approach, though,
I'd say make optional a model of a variant and/or discriminated union
concept that it and variant share, along with "expected" if it were to make
it into boost (I.E. allow for apply_visitor of T and none, provide a
"which"). I'd still like to see the other functions you mention as well for
convenience.

I know that there are others (Eric?) who prefer to think of optional as a
container of size 0 or 1, so it could also make sense to provide an
accessor to a range. One interesting effect of this is that now
range-based-for sort of becomes a "visit if." There are probably other...
interesting uses of standard algorithms.

> I would rather not go that way. boost::optional is not unsafe. It is
simply
> something else than what some people think. Its conceptual model is more
> like any value of T, plus one additional value. In this model implicit
> conversions make perfect sense and are n fact desirable.

I'm not sure I agree. These two templates aren't exactly complimentary in
terms of the functionality that they provide, they really would just
provide exactly the same functionality with the same internals. All that is
different is the interface. Because of that, I say either it replaces
optional or it doesn't exit as a part of boost. If people are convinced
that this interface is less error prone, then it should be THE interface
for optional.

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

Re: [optional] Safe optional

Robert Ramey
In reply to this post by Andrzej Krzemienski
Andrzej Krzemienski wrote
My idea is to provide another type wrapper, say safe_optional<T>, that
would choose different tradeoffs: prefer "safety" to some flexibility
and/or efficiency. It would probably be part of Boost.Optional library as
the implementation can be reused - only the interface would be changed.

One downside of this solution is that we would have two libraries for doing
nearly the same thing, which could "scatter" the community. There is a
value for standardizing certain things and making them universal.
Can't this concern be addressed by making this an addition to the optional library.
So that safe_optional<T> would be an wrapper around optional<T> with
extra error checking?

Robert Ramey
Reply | Threaded
Open this post in threaded view
|

Re: [optional] Safe optional

Joaquin M LópezMuñoz
In reply to this post by Andrzej Krzemienski
Andrzej Krzemienski <akrzemi1 <at> gmail.com> writes:

>
> No, no exceptions.
> The solution is based on the observation that there is a limited number of
> things you can do with optional<T>
>
> optional<int> oi = ...;
>
> 1:
> if (oi) doSomething(*oi);
> else doSomethingElse(); // or nothing
>
> 2:
> if (oi) doSomething(*oi);
> else doSomething(-1); // use default value
>
> 3:
> if (!oi) oi = (int)getIntByOtherMeans();
> doSomething(*oi); // now it is safe

Just to throw some idea in, there's an altenative based on the following
approach: let's assume we have a function f such as

  f(T1,...,T2)->ret

and we have arg1,...argn where the type of argi optional<T1>.
To call f we'd have to do something like

  auto ret=
    arg1&&arg2&&...&&argn?
    f(arg1.get(),...,argn.get()):
    none;

In fact, we could *lift* f so that we write this instead:

  auto ret=lift<f>(arg1,...,argn);

with the same semantics. This is a case of *monadic lifting* as
explained (and implemented) at

  http://bannalia.blogspot.com/2014/03/monadic-lifting-in-c.html

Lifting can be applied to regular functions as well as operator
such as the arithmetic ones (relational operators don't follow the
asme behavior). For the same price, lift<f> can accept any
combination of optional and non-optional args. Not sure this is
a case of interface augmentation that we want to apply to
boost::optional, but I felt like mentioning it at least.

Joaquin M López Muñoz
Telefónica


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

Re: [optional] Safe optional

Andrzej Krzemienski
In reply to this post by Robert Ramey
2014-11-17 18:01 GMT+01:00 Robert Ramey <[hidden email]>:

> Andrzej Krzemienski wrote
> > My idea is to provide another type wrapper, say safe_optional
> > <T>
> > , that
> > would choose different tradeoffs: prefer "safety" to some flexibility
> > and/or efficiency. It would probably be part of Boost.Optional library as
> > the implementation can be reused - only the interface would be changed.
> >
> > One downside of this solution is that we would have two libraries for
> > doing
> > nearly the same thing, which could "scatter" the community. There is a
> > value for standardizing certain things and making them universal.
>
> Can't this concern be addressed by making this an addition to the optional
> library.
> So that safe_optional<T> would be an wrapper around optional<T> with
> extra error checking?
>

In fact, Boost.Optional already comes with two interfaces:
1. optional_base<T> (with minimum set of operations)
2. optional<T> that derives from the former.

Although the former one is not advertized in the documentation, the intent
was that it is used by people who are not happy with the latter interface,
so they can use it to  build whatever interface they like. I was planning
to use optional_base as a base for the new interface. First, I want to see
peoples' reaction.

Regards,
&rzej

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

Re: [optional] Safe optional

Vladimir Batov-5
In reply to this post by Mostafa-6
On 11/17/2014 09:12 PM, Mostafa wrote:

> On Sun, 16 Nov 2014 23:04:43 -0800, Andrzej Krzemienski
> <[hidden email]> wrote:
>
>> Hi Everyone,
>> I would like to run an idea through everyone in this list. There is a
>> recurring complaint about Boost.Optional that it allows you to do
>> "unsafe"
>> things:
>> 1. Inadvertent mixed comparisons between T and optional<T>
>> 2. Unintended conversion from T to optional<T>
>
> The problem with optional is that it tries to be a drop-in replacement
> proxy for its underlying type, and, unfortunately, it can't fully do
> that. So it ends up with an identity crisis. IMO, optional should be
> treated as a first class object, not a thin wrapper around T, that
> means no implicit conversions to/from T, no implicit comparisons with
> T, etc... Last time I looked at this, that will solve the reference
> rebinding gotcha. That is, you'll have one behavior for optional<T>
> and optional<T&>....

1. With all due respect I do not feel I can agree with the above... and
I do not believe "optional" has a "problem"... especially of the
described magnitude. IMO the result of applying the conceptual/design
changes described above to the existing "optional" won't be "optional"
as we know it... not even close. And after using "optional" quite a bit
I can say I personally won't be very happy. IMO "optional" has been born
as a practical solution to a real problem and IMO it solves it quite
well. Yes, it has certain behavior that the user needs to be aware of...
but what class does not impose restrictions of that kind? Any potential
functional/behavioral change has to be looked at individually.

For example, I do agree that that there should not be implicit
optional<T> to T conversion. I was not even aware there was such.

However, implicit T to optional<T> conversion has a very practical
purpose. For example,

     int value(optional<int> =optional<int>());

allows me to shrink the API as value getter and setter are merged into
one function. Namely,

     int k = value(); // Get the value
     value(22); // Set the value. Implicit conversion of T to optional<T>

Instead, asking the user to call explicitly

     value(optional<22>)

is a professional suicide.

2. As for the separate/additional "safe" optional, I am personally not
that thrilled by the idea as of now. IMO that'll result in user-base
fragmentation, incompatibilities and inevitably more confusion in the end.

Just my 2c.


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

Re: [optional] Safe optional

Mostafa-6
On Mon, 17 Nov 2014 13:12:56 -0800, Vladimir Batov  
<[hidden email]> wrote:

> On 11/17/2014 09:12 PM, Mostafa wrote:
>> On Sun, 16 Nov 2014 23:04:43 -0800, Andrzej Krzemienski  
>> <[hidden email]> wrote:
>>
>>> Hi Everyone,
>>> I would like to run an idea through everyone in this list. There is a
>>> recurring complaint about Boost.Optional that it allows you to do  
>>> "unsafe"
>>> things:
>>> 1. Inadvertent mixed comparisons between T and optional<T>
>>> 2. Unintended conversion from T to optional<T>
>>
>> The problem with optional is that it tries to be a drop-in replacement  
>> proxy for its underlying type, and, unfortunately, it can't fully do  
>> that. So it ends up with an identity crisis. IMO, optional should be  
>> treated as a first class object, not a thin wrapper around T, that  
>> means no implicit conversions to/from T, no implicit comparisons with  
>> T, etc... Last time I looked at this, that will solve the reference  
>> rebinding gotcha. That is, you'll have one behavior for optional<T> and  
>> optional<T&>....
>
> 1. With all due respect I do not feel I can agree with the above... and  
> I do not believe "optional" has a "problem"... especially of the  
> described magnitude. IMO the result of applying the conceptual/design  
> changes described above to the existing "optional" won't be "optional"  
> as we know it... not even close.

Just to clarify, since the discussion is in the context of an "alternative  
optional", what I wrote about how the existing library should behave just  
applies to the alternative one.

> And after using "optional" quite a bit I can say I personally won't be  
> very happy. IMO "optional" has been born as a practical solution to a  
> real problem and IMO it solves it quite well. Yes, it has certain  
> behavior that the user needs to be aware of... but what class does not  
> impose restrictions of that kind?

Not all classes have gotchas. And, IMO, C++ has too many gotchas as it is.

> Any potential functional/behavioral change has to be looked at  
> individually.
>
> For example, I do agree that that there should not be implicit  
> optional<T> to T conversion. I was not even aware there was such.
>
> However, implicit T to optional<T> conversion has a very practical  
> purpose.

And that leads to the intractable rebinding gotcha for optional<T&>.

> For example,
>
>      int value(optional<int> =optional<int>());
>
> allows me to shrink the API as value getter and setter are merged into  
> one function. Namely,
>
>      int k = value(); // Get the value
>      value(22); // Set the value. Implicit conversion of T to optional<T>
> Instead, asking the user to call explicitly
>
>      value(optional<22>)
>
> is a professional suicide.

Templates are neither new nor unknown in C++. If you find yourself typing  
too much, just use a typedef.

> 2. As for the separate/additional "safe" optional, I am personally not  
> that thrilled by the idea as of now. IMO that'll result in user-base  
> fragmentation, incompatibilities and inevitably more confusion in the  
> end.

If there are multiple valid yet incompatible design choices, then IMO  
there is nothing wrong with providing alternatives.


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

Re: [optional] Safe optional

Vladimir Batov-5
On 11/18/2014 11:25 AM, Mostafa wrote:

> On Mon, 17 Nov 2014 13:12:56 -0800, Vladimir Batov
> <[hidden email]> wrote:
>> On 11/17/2014 09:12 PM, Mostafa wrote:
>>> On Sun, 16 Nov 2014 23:04:43 -0800, Andrzej Krzemienski
>>> <[hidden email]> wrote:
>>>> Hi Everyone,
>>>> I would like to run an idea through everyone in this list. There is a
>>>> recurring complaint about Boost.Optional that it allows you to do
>>>> "unsafe"
>>>> things:
>>>> 1. Inadvertent mixed comparisons between T and optional<T>
>>>> 2. Unintended conversion from T to optional<T>
>>>
...
>> And after using "optional" quite a bit I can say I personally won't
>> be very happy. IMO "optional" has been born as a practical solution
>> to a real problem and IMO it solves it quite well. Yes, it has
>> certain behavior that the user needs to be aware of... but what class
>> does not impose restrictions of that kind?
>
> Not all classes have gotchas. And, IMO, C++ has too many gotchas as it
> is.

Well, that's far too broad a statement to be argued over... still, my
logic behind restrictions-related statement is that, say, a class
provides a service, nothing is free, so to make use of the service the
user needs to give something back... be that adhering to certain
deployment pattern or API or something.

>
>> Any potential functional/behavioral change has to be looked at
>> individually.
>>
>> For example, I do agree that that there should not be implicit
>> optional<T> to T conversion. I was not even aware there was such.
>>
>> However, implicit T to optional<T> conversion has a very practical
>> purpose.
>
> And that leads to the intractable rebinding gotcha for optional<T&>.

Yes, I've heard of that "beast". In all honesty to me it looks quite
esoteric and beyond the realm of practical every-day programming. I
suspect if it's taken out altogether, 95% of the users will not even
notice. I can be wrong though and prepared to be convinced otherwise...
if you show me a practical example where it's a must-have... Without
such I fully understand/support the decision to get rid of optional<T&>
for std::tr2::optional proposal. So, re-phrasing J. Stalin's "no man, no
problem" -- "no "feature", no problem.


>
>> For example,
>>
>>      int value(optional<int> =optional<int>());
>>
>> allows me to shrink the API as value getter and setter are merged
>> into one function. Namely,
>>
>>      int k = value(); // Get the value
>>      value(22); // Set the value. Implicit conversion of T to
>> optional<T>
>> Instead, asking the user to call explicitly
>>
>>      value(optional<22>)
>>
>> is a professional suicide.
>
> Templates are neither new nor unknown in C++. If you find yourself
> typing too much, just use a typedef.

Hmm, not sure I follow what templates have to do with it... and the
amount of typing is irrelevant. The point was if conceptually user
expects to use/deal with "int", then the requirement to explicitly
specify optional<int> looks unreasonably heavy and unnatural. It exposes
too much underlying infrastructure where it does not need to. All IMO of
course.

>
>> 2. As for the separate/additional "safe" optional, I am personally
>> not that thrilled by the idea as of now. IMO that'll result in
>> user-base fragmentation, incompatibilities and inevitably more
>> confusion in the end.
>
> If there are multiple valid yet incompatible design choices, then IMO
> there is nothing wrong with providing alternatives.

I do not believe it's that simple. If, when referring to "incompatible
design choices", we are talking about differences like "car vs. truck",
then I'd argue that those are not alternatives as they serve quite
distinct purposes and, therefore, adhere to different designs.
Otherwise, having "incompatible design choices" like a toothbrush and a
"safe" toothbrush and a "whistling" toothbrush are distracting and
confusing and IMO counter-productive. I had an impression that "safe"
optional suggestion was more in the latter camp as it still very much
wanted to be "optional"... but a tiny bit different. It  might well be
that I misunderstood.



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

Re: [optional] Safe optional

Mostafa-6
On Mon, 17 Nov 2014 19:57:08 -0800, Vladimir Batov  
<[hidden email]> wrote:

> On 11/18/2014 11:25 AM, Mostafa wrote:
>> On Mon, 17 Nov 2014 13:12:56 -0800, Vladimir Batov  
>> <[hidden email]> wrote:
>>> On 11/17/2014 09:12 PM, Mostafa wrote:
>>>> On Sun, 16 Nov 2014 23:04:43 -0800, Andrzej Krzemienski  
>>>> <[hidden email]> wrote:
>>>>> Hi Everyone,
>>>>> I would like to run an idea through everyone in this list. There is a
>>>>> recurring complaint about Boost.Optional that it allows you to do  
>>>>> "unsafe"
>>>>> things:
>>>>> 1. Inadvertent mixed comparisons between T and optional<T>
>>>>> 2. Unintended conversion from T to optional<T>
>>>>
> ...
>>> And after using "optional" quite a bit I can say I personally won't be  
>>> very happy. IMO "optional" has been born as a practical solution to a  
>>> real problem and IMO it solves it quite well. Yes, it has certain  
>>> behavior that the user needs to be aware of... but what class does not  
>>> impose restrictions of that kind?
>>
>> Not all classes have gotchas. And, IMO, C++ has too many gotchas as it  
>> is.
>
> Well, that's far too broad a statement to be argued over... still, my  
> logic behind restrictions-related statement is that, say, a class  
> provides a service, nothing is free, so to make use of the service the  
> user needs to give something back... be that adhering to certain  
> deployment pattern or API or something.

I'm in agreement with the last sentence. What I'm saying is that the  
current optional usage pattern, IMHO, is just too inconsistent.

>>> Any potential functional/behavioral change has to be looked at  
>>> individually.
>>>
>>> For example, I do agree that that there should not be implicit  
>>> optional<T> to T conversion. I was not even aware there was such.
>>>
>>> However, implicit T to optional<T> conversion has a very practical  
>>> purpose.
>>
>> And that leads to the intractable rebinding gotcha for optional<T&>.
>
> Yes, I've heard of that "beast". In all honesty to me it looks quite  
> esoteric and beyond the realm of practical every-day programming. I  
> suspect if it's taken out altogether, 95% of the users will not even  
> notice. I can be wrong though and prepared to be convinced otherwise...  
> if you show me a practical example where it's a must-have... Without  
> such I fully understand/support the decision to get rid of optional<T&>  
> for std::tr2::optional proposal. So, re-phrasing J. Stalin's "no man, no  
> problem" -- "no "feature", no problem.

And that exacerbates the problem doesn't it? If optional<T&> is just used  
5% of the time, then when that particular gotcha is hit, it'll be that  
much harder to diagnose the issue. Not all programmers are full time C++  
programmers, not all programmers develop new code full time, some do quite  
a bit of maintenance, so not everyone is going to be an expert in the ins  
and outs of any particular library. The simpler a library is to use, the  
simpler it will be to maintain the code which uses it.

>>> For example,
>>>
>>>      int value(optional<int> =optional<int>());
>>>
>>> allows me to shrink the API as value getter and setter are merged into  
>>> one function. Namely,
>>>
>>>      int k = value(); // Get the value
>>>      value(22); // Set the value. Implicit conversion of T to  
>>> optional<T>
>>> Instead, asking the user to call explicitly
>>>
>>>      value(optional<22>)
>>>
>>> is a professional suicide.
>>
>> Templates are neither new nor unknown in C++. If you find yourself  
>> typing too much, just use a typedef.
>
> Hmm, not sure I follow what templates have to do with it... and the  
> amount of typing is irrelevant. The point was if conceptually user  
> expects to use/deal with "int", then the requirement to explicitly  
> specify optional<int> looks unreasonably heavy and unnatural.

Then why specify in the interface in the first place?

>>> 2. As for the separate/additional "safe" optional, I am personally not  
>>> that thrilled by the idea as of now. IMO that'll result in user-base  
>>> fragmentation, incompatibilities and inevitably more confusion in the  
>>> end.
>>
>> If there are multiple valid yet incompatible design choices, then IMO  
>> there is nothing wrong with providing alternatives.
>
> I do not believe it's that simple. If, when referring to "incompatible  
> design choices", we are talking about differences like "car vs. truck",  
> then I'd argue that those are not alternatives as they serve quite  
> distinct purposes and, therefore, adhere to different designs.  
> Otherwise, having "incompatible design choices" like a toothbrush and a  
> "safe" toothbrush and a "whistling" toothbrush are distracting and  
> confusing and IMO counter-productive. I had an impression that "safe"  
> optional suggestion was more in the latter camp as it still very much  
> wanted to be "optional"... but a tiny bit different. It  might well be  
> that I misunderstood.

They will be competing libraries. But I don't see that as a bad thing. It  
will only be confusing if the rationale for their difference is not well  
documented.


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

Re: [optional] Safe optional

Vicente Botet
In reply to this post by Andrzej Krzemienski
Le 17/11/14 10:24, Andrzej Krzemienski a écrit :

> 2014-11-17 9:40 GMT+01:00 Matt Calabrese <[hidden email]>:
>
>> On Sun, Nov 16, 2014 at 11:04 PM, Andrzej Krzemienski <[hidden email]>
>> wrote:
>>
>>> Hi Everyone,
>>> I would like to run an idea through everyone in this list. There is a
>>> recurring complaint about Boost.Optional that it allows you to do
>> "unsafe"
>>> things:
>>> 1. Inadvertent mixed comparisons between T and optional<T>
>>> 2. Unintended conversion from T to optional<T>
>>> 3. "Unchecked" access to the contained object, which causes an UB when
>>> performed on an uninitialized optional object.
>>>
>>> There are valid reasons why optional is defined the way it is defined.
>> But
>>> at the same time the complaints above are also valid. This makes some
>>> people abandon Boost.Optional and use their own alternative.
>>>
>> I don't immediately see the problem with the mixed comparisons between T
>> and optional T... except maybe confusion regarding optional<bool> or
>> bool-like types. Is this what you're referring to? If so, then I sort of
>> disagree that it's a legitimate problem. If you are not talking about
>> issues relating to bool or have some really compelling optional<bool>
>> cases, can you point me to examples as to why this is suggested to be
>> unsafe. I don't really care that much about the mixed comparisons, but I
>> consider them pretty benign and if people find it useful then I won't
>> remove it unless the current uses are fully considered.
>>
>> As for #2, I think I agree that conversion should probably be more explicit
>> and is potentially a step in a positive direction.
>>
>> As for #3, if you are implying the alternative is to throw an exception,
>> then I'd say that's a flat-out no. That's a logic error and we shouldn't
>> throw an exception. The only thing that comes of that is people using the
>> exception for basic control flow -- if they knew the optional didn't point
>> to anything, then they wouldn't be dereferencing it. If they THOUGHT the
>> optional pointed to something and it didn't, then they have a bug, which
>> means the way to "handle" it is to fix the code. If they don't know at the
>> time of the access whether there was something there or not, then they
>> shouldn't deference it, using an exception for control flow. In that last
>> case, they should either be explicitly branching or they should use some
>> kind of visitation. If you're not talking about exceptions, then what
>> exactly are you proposing?
>>
> No, no exceptions.
> The solution is based on the observation that there is a limited number of
> things you can do with optional<T>
>
> optional<int> oi = ...;
>
> 1:
> if (oi) doSomething(*oi);
> else doSomethingElse(); // or nothing
>
> 2:
> if (oi) doSomething(*oi);
> else doSomething(-1); // use default value
>
> 3:
> if (!oi) oi = (int)getIntByOtherMeans();
> doSomething(*oi); // now it is safe
>
> Now we simply provide a dedicated interface for each of these three usages:
>
> 1:
> oi.use(&doSomething, &doSomethingElse); // or use lambdas
This is the idea of visitation and try-catch behind this function. What
would be the result of this use function? Should both functions return
the same type?

I would suggest to call this accept or match. In addition this could be
a free function

auto x = match(oi,
     [] (int i) {},
     [] () {}
);
The function could take several optional

auto x = match(make_tuple(oi, os),
     [] (int i, string const& s) {},
     [] (...) {}
);

>
> 2:
> doSomething(oi.value_or(-1));
I believed this was already part of the interface.


>
> 3:
> doSomething(oi.value_or_eval(getIntByOtherMeans));
>
>


Why do we need a new safe_optional class to add these features?

Best,
Vicente

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

Re: [optional] Safe optional

Vicente Botet
In reply to this post by Matt Calabrese
Le 17/11/14 17:41, Matt Calabrese a écrit :

> On Nov 17, 2014 1:25 AM, "Andrzej Krzemienski" <[hidden email]> wrote:
>> No, no exceptions.
>> The solution is based on the observation that there is a limited number of
>> things you can do with optional<T>
>>
>> optional<int> oi = ...;
>>
>> 1:
>> if (oi) doSomething(*oi);
>> else doSomethingElse(); // or nothing
>>
>> 2:
>> if (oi) doSomething(*oi);
>> else doSomething(-1); // use default value
>>
>> 3:
>> if (!oi) oi = (int)getIntByOtherMeans();
>> doSomething(*oi); // now it is safe
>>
>> Now we simply provide a dedicated interface for each of these three
> usages:
>> 1:
>> oi.use(&doSomething, &doSomethingElse); // or use lambdas
>>
>> 2:
>> doSomething(oi.value_or(-1));
>>
>> 3:
>> doSomething(oi.value_or_eval(getIntByOtherMeans));
> While I agree that we should be encouraging high order functions/visitation
> here, my personal experience is simply that many people do not like it.
> When given the choice to pass a lamda or to use an "if" or a
> range-based-for over high order function alternatives, programmers will
> generally opt for not using a lambda. The fact that Bjarne thinks
> visitation is somehow "bad" doesn't help. I agree that it's safer and I'd
> be in favor of it, but be aware that not everyone will like it.
I will ad that I believe Dr BS don't like dynamic visitation, but here
we are doing pattern matching on types, isn't it?
>
> That said, I'd be in favor of this. If going with this approach, though,
> I'd say make optional a model of a variant and/or discriminated union
> concept that it and variant share, along with "expected" if it were to make
> it into boost (I.E. allow for apply_visitor of T and none, provide a
> "which"). I'd still like to see the other functions you mention as well for
> convenience.

Yes, all these types a sum types, so any feature in the scope of sum
types can be applied to all of them.
In addition, one of the optional sum types is a non-a-value, and there
is a lot of common thing for such types probably valued types. expected
shares a lot with optional, but it in not the only one e.g. T*.

The current problem we have with our TBoost.Expected is that we don't
have an implementation for C++98 compilers :(
If the Boost community can accept a C++11 only library I'll be glad to
work on preparing it for review.
Is there any one that wants to work on a branch to port it to C++98
compilers?

>
> I know that there are others (Eric?) who prefer to think of optional as a
> container of size 0 or 1, so it could also make sense to provide an
> accessor to a range. One interesting effect of this is that now
> range-based-for sort of becomes a "visit if." There are probably other...
> interesting uses of standard algorithms.
>
>> I would rather not go that way. boost::optional is not unsafe. It is
> simply
>> something else than what some people think. Its conceptual model is more
>> like any value of T, plus one additional value. In this model implicit
>> conversions make perfect sense and are n fact desirable.
> I'm not sure I agree. These two templates aren't exactly complimentary in
> terms of the functionality that they provide, they really would just
> provide exactly the same functionality with the same internals. All that is
> different is the interface. Because of that, I say either it replaces
> optional or it doesn't exit as a part of boost. If people are convinced
> that this interface is less error prone, then it should be THE interface
> for optional.
>
Andrzej, I think I see what you meant by a safe_optional. A safe optional wouldn't provide direct access to the value.  (Sorry I need sometime to understand things).

Couldn't safe_optional just be a wrapper of optional restricting its interface? safe_optional could be explicitly convertible to optional and optional implicitly convertible to safe_optional.

Instead of safe_optional I would prefer to don't use the safe_ prefix, as optional is safe already. IIUC, safe_optional is limited to a monad interface and whatever we can build on top of it. What about monad_optional<T> or monad::optional<T>?

@Matt I don't think we need to choose instead of the user. We have here two complementary interface to the same data, there is no one better than the other. Up to the user to choose the one more adapted to his needs.

Best,
Vicente


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

Re: [optional] Safe optional

Andrey Semashev-2
In reply to this post by Andrzej Krzemienski
On Mon, Nov 17, 2014 at 12:24 PM, Andrzej Krzemienski
<[hidden email]> wrote:

>
> The solution is based on the observation that there is a limited number of
> things you can do with optional<T>
>
> optional<int> oi = ...;
>
> 1:
> if (oi) doSomething(*oi);
> else doSomethingElse(); // or nothing
>
> 2:
> if (oi) doSomething(*oi);
> else doSomething(-1); // use default value
>
> 3:
> if (!oi) oi = (int)getIntByOtherMeans();
> doSomething(*oi); // now it is safe
>
> Now we simply provide a dedicated interface for each of these three usages:
>
> 1:
> oi.use(&doSomething, &doSomethingElse); // or use lambdas

I'd call it visit(). Also, a one argument visit() could be useful (the
visitor would be passed boost::none if the value is absent).

> 2:
> doSomething(oi.value_or(-1));

We already have that.

> 3:
> doSomething(oi.value_or_eval(getIntByOtherMeans));

So, basically, the proposal is to add visitation API, am I correct? In
that case why not add it to the regular optional?

IMHO, in order to introduce an alternative component, there should be
significant and incompatible design and interface differences between
the two. So far I don't see the need for such differences.

>> Regardless, if people come to an agreement on changes, I'm much more in
>> favor of simply making breaking changes to the current optional rather than
>> introducing another one. It's unfortunate for a type as fundamental and
>> widely used as optional, but people will get over it, especially if it
>> makes it closer to the standard proposal.
>
> I would rather not go that way. boost::optional is not unsafe. It is simply
> something else than what some people think. Its conceptual model is more
> like any value of T, plus one additional value. In this model implicit
> conversions make perfect sense and are n fact desirable.

Exactly. Vladimir's example is an illustration of this.

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

Re: [optional] Safe optional

Vicente Botet
In reply to this post by Vladimir Batov-5
Le 17/11/14 22:12, Vladimir Batov a écrit :

> On 11/17/2014 09:12 PM, Mostafa wrote:
>> On Sun, 16 Nov 2014 23:04:43 -0800, Andrzej Krzemienski
>> <[hidden email]> wrote:
>>
>>> Hi Everyone,
>>> I would like to run an idea through everyone in this list. There is a
>>> recurring complaint about Boost.Optional that it allows you to do
>>> "unsafe"
>>> things:
>>> 1. Inadvertent mixed comparisons between T and optional<T>
>>> 2. Unintended conversion from T to optional<T>
>>
>> The problem with optional is that it tries to be a drop-in
>> replacement proxy for its underlying type, and, unfortunately, it
>> can't fully do that. So it ends up with an identity crisis. IMO,
>> optional should be treated as a first class object, not a thin
>> wrapper around T, that means no implicit conversions to/from T, no
>> implicit comparisons with T, etc... Last time I looked at this, that
>> will solve the reference rebinding gotcha. That is, you'll have one
>> behavior for optional<T> and optional<T&>....
>
> 1. With all due respect I do not feel I can agree with the above...
> and I do not believe "optional" has a "problem"... especially of the
> described magnitude. IMO the result of applying the conceptual/design
> changes described above to the existing "optional" won't be "optional"
> as we know it... not even close. And after using "optional" quite a
> bit I can say I personally won't be very happy. IMO "optional" has
> been born as a practical solution to a real problem and IMO it solves
> it quite well. Yes, it has certain behavior that the user needs to be
> aware of... but what class does not impose restrictions of that kind?
> Any potential functional/behavioral change has to be looked at
> individually.
>
> For example, I do agree that that there should not be implicit
> optional<T> to T conversion. I was not even aware there was such.
This conversion must be explicit if any.

>
> However, implicit T to optional<T> conversion has a very practical
> purpose. For example,
>
>     int value(optional<int> =optional<int>());
>
> allows me to shrink the API as value getter and setter are merged into
> one function. Namely,
>
>     int k = value(); // Get the value
>     value(22); // Set the value. Implicit conversion of T to optional<T>
>
Please don't do that. Use just overload.

> Instead, asking the user to call explicitly
>
>     value(optional<22>)
>
> is a professional suicide.
>
> 2. As for the separate/additional "safe" optional, I am personally not
> that thrilled by the idea as of now. IMO that'll result in user-base
> fragmentation, incompatibilities and inevitably more confusion in the
> end.
Anything useful for safe_optional is useful for optional. So I see
safe_optional as a view of a restricted interface.
This doesn't mean that conversions from one to the other are not possible.

Vicente

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

Re: [optional] Safe optional

Matt Calabrese
In reply to this post by Vicente Botet
On Mon, Nov 17, 2014 at 10:59 PM, Vicente J. Botet Escriba <
[hidden email]> wrote:

>
>>  I will ad that I believe Dr BS don't like dynamic visitation, but here
> we are doing pattern matching on types, isn't it?


For a while I assumed exactly that, but he actually specifically voiced
that he does not like visitation on variant and thinks of it as a hack.
It's sad :/


> @Matt I don't think we need to choose instead of the user. We have here
> two complementary interface to the same data, there is no one better than
> the other. Up to the user to choose the one more adapted to his needs.


I'm still not really sure I agree. I see no problem with things like
Boost.MSM and Boost.Statechart both being in Boost, as while they solve
many of the same problems they each have very clear advantages and
disadvantages. I'm actually very much in favor of stuff like that.

On the other hand, safe_optional and optional would basically be two
templates that have identical implementation with just different
interfaces. If you can say objective things about one being safer, and all
else is equal, then it should be THE library and the old optional should be
deprecated. I don't think it's worth having two libraries when they are so
similar.


--
-Matt Calabrese

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

Re: [optional] Safe optional

Matt Calabrese
On Mon, Nov 17, 2014 at 11:16 PM, Matt Calabrese <[hidden email]> wrote:

> On the other hand, safe_optional and optional would basically be two
> templates that have identical implementation with just different
> interfaces. If you can say objective things about one being safer, and all
> else is equal, then it should be THE library and the old optional should be
> deprecated. I don't think it's worth having two libraries when they are so
> similar.
>

Also, to be clear, I'm not saying I believe that safe_optional is
necessarily the right way to go, I just think that if it were to be decided
that it is worthwhile, it should probably just replace optional. I'm not
entirely convinced that it's really worth a new template, though.
Ultimately I think it's probably best to simply create/evangelize
high-order visitation accessors and have them work with the existing
optional. Then just be clear in documentation that their use is recommended
over raw access. It's the same with variant and I don't think that's a
problem -- encourage visitation, but allow direct access.

--
-Matt Calabrese

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

Re: [optional] Safe optional

Andrzej Krzemienski
In reply to this post by Vicente Botet
2014-11-18 7:22 GMT+01:00 Vicente J. Botet Escriba <[hidden email]
>:

> Le 17/11/14 10:24, Andrzej Krzemienski a écrit :
>
>  2014-11-17 9:40 GMT+01:00 Matt Calabrese <[hidden email]>:
>>
>>  On Sun, Nov 16, 2014 at 11:04 PM, Andrzej Krzemienski <
>>> [hidden email]>
>>> wrote:
>>>
>>>  Hi Everyone,
>>>> I would like to run an idea through everyone in this list. There is a
>>>> recurring complaint about Boost.Optional that it allows you to do
>>>>
>>> "unsafe"
>>>
>>>> things:
>>>> 1. Inadvertent mixed comparisons between T and optional<T>
>>>> 2. Unintended conversion from T to optional<T>
>>>> 3. "Unchecked" access to the contained object, which causes an UB when
>>>> performed on an uninitialized optional object.
>>>>
>>>> There are valid reasons why optional is defined the way it is defined.
>>>>
>>> But
>>>
>>>> at the same time the complaints above are also valid. This makes some
>>>> people abandon Boost.Optional and use their own alternative.
>>>>
>>>>  I don't immediately see the problem with the mixed comparisons between
>>> T
>>> and optional T... except maybe confusion regarding optional<bool> or
>>> bool-like types. Is this what you're referring to? If so, then I sort of
>>> disagree that it's a legitimate problem. If you are not talking about
>>> issues relating to bool or have some really compelling optional<bool>
>>> cases, can you point me to examples as to why this is suggested to be
>>> unsafe. I don't really care that much about the mixed comparisons, but I
>>> consider them pretty benign and if people find it useful then I won't
>>> remove it unless the current uses are fully considered.
>>>
>>> As for #2, I think I agree that conversion should probably be more
>>> explicit
>>> and is potentially a step in a positive direction.
>>>
>>> As for #3, if you are implying the alternative is to throw an exception,
>>> then I'd say that's a flat-out no. That's a logic error and we shouldn't
>>> throw an exception. The only thing that comes of that is people using the
>>> exception for basic control flow -- if they knew the optional didn't
>>> point
>>> to anything, then they wouldn't be dereferencing it. If they THOUGHT the
>>> optional pointed to something and it didn't, then they have a bug, which
>>> means the way to "handle" it is to fix the code. If they don't know at
>>> the
>>> time of the access whether there was something there or not, then they
>>> shouldn't deference it, using an exception for control flow. In that last
>>> case, they should either be explicitly branching or they should use some
>>> kind of visitation. If you're not talking about exceptions, then what
>>> exactly are you proposing?
>>>
>>>  No, no exceptions.
>> The solution is based on the observation that there is a limited number of
>> things you can do with optional<T>
>>
>> optional<int> oi = ...;
>>
>> 1:
>> if (oi) doSomething(*oi);
>> else doSomethingElse(); // or nothing
>>
>> 2:
>> if (oi) doSomething(*oi);
>> else doSomething(-1); // use default value
>>
>> 3:
>> if (!oi) oi = (int)getIntByOtherMeans();
>> doSomething(*oi); // now it is safe
>>
>> Now we simply provide a dedicated interface for each of these three
>> usages:
>>
>> 1:
>> oi.use(&doSomething, &doSomethingElse); // or use lambdas
>>
> This is the idea of visitation and try-catch behind this function. What
> would be the result of this use function? Should both functions return the
> same type?
>
> I would suggest to call this accept or match. In addition this could be a
> free function
>
> auto x = match(oi,
>     [] (int i) {},
>     [] () {}
> );
> The function could take several optional
>
> auto x = match(make_tuple(oi, os),
>     [] (int i, string const& s) {},
>     [] (...) {}
> );
>
>
>> 2:
>> doSomething(oi.value_or(-1));
>>
> I believed this was already part of the interface.
>
>
>
>> 3:
>> doSomething(oi.value_or_eval(getIntByOtherMeans));
>>
>>
>>


> Why do we need a new safe_optional class to add these features?
>

Because once we have the three above (2 and 3 already present in
boost::optional) we can remove all other interface that has a potential to
cause confusion or UB.


>
> Best,
> Vicente
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/
> mailman/listinfo.cgi/boost
>

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