Boost logo

Boost :

From: Fernando Cacciola (fernando_cacciola_at_[hidden])
Date: 2002-12-12 13:22:12


----- Original Message -----
From: "Peter Dimov" <pdimov_at_[hidden]>
To: "Boost mailing list" <boost_at_[hidden]>
Sent: Thursday, December 12, 2002 1:00 PM
Subject: Re: [boost] Formal review: Optional library

> From: "Fernando Cacciola" <fernando_cacciola_at_[hidden]>
> > > Yes, I thought about that, too. But if the current swap semantics are
> > > retained, it should simply be removed. Otherwise optional<T>::swap
must
> > > offer at least swap(T&, T&)'s guarantee.
> > >
> > I'm not sure I follow.
> > What are swap(T&, T&) guarantees in general?
> > I thought this depended on the specific type.
>
> True, swap()'s guarantees depend on the type. If T provides a
> nothrow/strong/basic swap, optional<T>::swap should be at least
> nothrow/strong/basic, respectively. I think that this can be done provided
> that T(T const &) is strong and T::~T is nothrow.
>
I still have to tink about this ...

> > Anyway, as I posted recently, I'm just about to conclude that relational
> > operators
> > could be properly defined as a synonim for: get_pointer(o1) .relop.
> > get_pointer(o2).
> > I found this definition totally consistent with pointer semantics and
the
> > implied
> > aliasings.
>
> Optional does not have pointer semantics.
>
Not _entirely_, sure; but I think it can be accurately said
that it has _partly_ pointer semantics, which is reflected
by its pointer-like interface, and _partly_ value semantics,
which is reflected by its container-like interface.

Precisely because its dual nature can be confusing,
it is very important that boths parts of the interface,
which reflect different semantics, can be unambiguously
differentiated so the actual semantic can be inferred
without doubts.

In order to achieve this, I considered fundamental the following
rule of thumb:
If optional<> is replaced by a pointer, and provided that uninitialized
optionals are defined as null pointers, any exression using optionals
should either fail to compile or behave exactly the same.
This rule allows the programmer to unambiguously infer the
semantic of a given expression using optional.

> Two optionals can never alias each
> other.
Unless they are both uninitialized or are actually the same.

> "Consistent with pointer semantics" doesn't make sense.
Why?
The pointer-like interface associates a pointer value to an optional object.
Having relop be defined to compare this pointer value makes just as much
sense
as having operator*() dereference this pointer, having operator-> return it,
etc...

>Optional is not a pointer. Don't try to make it into one; you'll arrive at
shared_ptr.
> ;-)
>
It is not completely a pointer, neither is not completely not a pointer. :-)

In fact, shared_ptr<> can well be used to convey the same optionality of a
value.
This is important: in an optional-less world, pointers and smart-pointers
are used
to handle optional values.
This makes a lot of sense and works pretty well in many situations.
It is actually the choice of value _storage_ which decides whether to
use optional<> or shared_ptr<>. If it makes sense to allocate the optional
object
dynamically, then using shared_ptr<> is a very good choice; but if the
ubiquity of
the type makes a dynamic allocation wastefull, go with optional<>.
But from the reciever POV, it should be the same whether a builtin pointer,
a smart pointer, or optional was used.
This is why the poiner-like interface is important.

The difference between using a pointer (smart or not) or using optional
shall
not be found on the operations that access the value, this is unnecesary.
The difference shall be in the way the value is wrapped: optional<> uses
value
semantics for this part, which is what makes it usefull, since it saves you
from
a wastefull and protocolar dynamic allocation/deallocation; but that's is
its
fundamental purpose; for the rest, familliar smart-pointer semantics are
appropiate.

Thus, optional<> uses a pointer-like interface for everthing except those
operations that deal with initializing, replacing and uninitializing the
value.

I know that (*o1==*o2) is undefined for uninitialized optionals,
but this is equally undefined for pointers, so I don't see it as
such a big problem.
optional<> is not intended to replace _all_ situations were optional values
are used.
It is itended to be used on those situations were pointers are difficult to
use;
but I expect programmers to keep using pointers were appropriate.
For example, as I said before, optional arguments to a function should not
be coded
with optional<> but with conventional pointers.
Therefore, the shortcut which is gained by having (o1==o2) compare values,
handling
uninitialized cases, is in itself very useful, but gives optional<> a
peculiarity
which spoils its ubiquity.

Fernando Cacciola


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