Boost logo

Boost :

From: Fernando Cacciola (fernando_cacciola_at_[hidden])
Date: 2002-12-11 09:52:06


----- Original Message -----
From: "William E. Kempf" <wekempf_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Tuesday, December 10, 2002 7:04 PM
Subject: Re: [boost] Formal review: Optional library

>
> Fernando Cacciola said:
>
> > But if I wrote:
> >
> > optional<int> x = foo();
> > if ( x )
> > some(x);
> >
> > it really looked as if it were testing if 'x' is initialized
> > while it was acutally comparing the 'x' value against 0.
>
> I'm not sure I find this compelling. Knowing that a test for
> initialization is done through optional::initialized(), I'd never mistake
> the if above for testing this. This would cause problems only with
> someone unfamiliar with optional, but they are going to have problems no
> matter what interface you choose until they read the documentation.
>
... but I would make such mistakes, and I know too many people that would
also do it.

> > Eventually, I realized that value semantics are not really appropiate to
> > deal
> > with unininitialized states since it blurs the distinction between
> > testing against other values and testing whether it is initialized or
> > not. So I wonder which other semantics would deal with it properly,
> > and pointers poped into my mind quickly.
>
> But pointers are just the inverse of the problem above. Test for validity
> is bald.

Only if safe_bool isn't used.
But, I'm just about to be convinced to added it, in which case,
test for validity will look just like it looks like
for any other smart/bare pointer.

>, while access to the "value" requires some supporting syntax (in
> this case, operator*). This leaves users in the exact same scenario where
> a simple mistake leads to code that compiles but doesn't do what the
> programmer meant.

Can you give me an example of something that compiles but
doesn't do what the programmer meant?
Remeber that currently *opt=x is defined even if opt is uninitialized

> I think you're trying just a little too hard to make
> the interface "idiot proof".
>
Fair enough. I tend to do this, I know.
Maybe is becasue I use to work late at night, so I better protect myself
from myself :-))

> >> Now, assuming we stick with pointer semantics, let's make this as
> >> close to the "normal" smart pointer interface as possible:
> >>
> >> template <typename T>
> >> class optional
> >> {
> >> public:
> >> optional();
> >> explicit optional(T const& value);
> >> optional(optional const& other);
> >> template <typename U>
> >> optional(optional<U> const& other);
> >> ~optional();
> >>
> >> T& operator*() const;
> >> T* operator->() const;
> >> T* get() const;
> >> // T* release();
> >> void reset();
> >> void reset(T const& value);
> >> operator unspecified-bool-type() const;
> >> };
> >>
> >>
> > This interface is greatly simplified mainly because
> > my interface offers deep-constantness:
> >
> > T const* peek() const ;
> > T* peek();
> > T const& operator*() const;
> > prxy operator*() ;
> >
> > instead of:
> >
> > T* peek() const ;
> > T& operator*() const;
> >
> > The proxy is needed *only* to achieve deep-constantness.
> > If this feature weren't introduced, my interface would have looked just
> > like yours.
>
> I still don't see the need for the proxy. The interface I gave could
> provide "deep-constantness" with out a proxy. I'm not sure where I stand
> on whether or not optional<> should provide this, however.
>
Right. I mistakenly forgot what the proxy is for...
it has nothing to do with deep-constantness... o-)
it is required to support *opt=x for uninitialized optionals, which reset
'opt'
to initilized.

But wait....
I will have to discuss this feature (?) on its own, so I'll top post this
issue.

> >> Semantics and rationale:
> >>
> >> optional()
> >>
> >> Constructs an "uninitialized" optional.
> >>
> >> explicit optional(T const& value)
> >>
> >> Constructs an optional initialized to value through copy
> >> construction.
> >>
> >> optional(optional const& other)
> >>
> >> Copy constructs an optional using the value-type's copy
> >> constructor.
> >>
> >> template <typename U> optional(optional<U> const& other)
> >>
> >> Allows copy construction from "compatible" optionals (optionals
> >> with
> >> value types that can be used for constructing this optional's value
> >> type). I'm not sure how important this one is for optional, to be
> >> honest.
> >>
> > I've never needed to convert between optinals.
> > On a related note, if deep-constantess is not supported
> > (as in your interface), an implicit conversion from
> > optional<T> to optional<T const> is needed because
> > the user will have to use <T const> to attach constantess
> > to the value.
>
> Actually, it's still not needed.
>
> optional<int> opt1(666);
> optional<const int> opt2(*opt1);
>
> Granted, it *IS* an important convenience, since you don't have to check
> the initialized state, but it's not strictly necessary.
?
Did you mean that conversion from <T> to <T const> can only be explicit?
Otherwise we said the same: there has to be a mechanism to convert from <T>
to <T const>

>
> >> ~optional()
> >>
> >> If the optional is initialized, calls the value-type's destructor.
> >>
> >
> > Why isn't assignment supplied?
>
> Because I believe the reset is clearer, and safer.
>
I see.
We'll get back to this reset() issue on the post about: uninitialized
assignment
(doing *opt=x when opt is uninitialized)

Fernando Cacciola


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