Boost logo

Boost :

From: Fernando Cacciola (fernando_cacciola_at_[hidden])
Date: 2002-12-13 14:36:39


----- Original Message -----
From: "Dave Gomboc" <dave_at_[hidden]>
To: "Boost Mailing List" <boost_at_[hidden]>
Sent: Thursday, December 12, 2002 11:19 PM
Subject: [boost] (corrected) review of optional library

> Adjusted at five points; please ignore the previous one.
>
> ---------- Forwarded message ----------
> At this point in time, I vote to reject the library. My vote is based
> upon a review of the interface and implementation in optional.hpp of the
> zip file I downloaded from the link posted by Fernando on Dec. 12, and
> following the discussion via the mailing list digests. I will qualify my
> vote by indicating that this is my first review for boost.
>
Welcome!

> The interface is undergoing a considerable amount of flux during the
> review period, and I think that significantly more change is still
> required before I would vote for its inclusion.
>
I understand. I as said in my previous post, we better reject it until we
do find a well thought interface.

> The operators that (unsuccessfully) attempt to provide pointer semantics
> are misleading, and should be removed. To me, appeals to optional being a
> container (or giving it pointer semantics, as if it were an iterator!)
> are misguided.
>
Point taken.
It is consufing, granted. Wouldn't say that misleading though.

> In my opinion, optional<T> [which perhaps ought to be may_be<T> or
> maybe<T>, as an earlier poster suggested, also see below]

The class name can be reconsidered, yes, on the light of this precedence.
But I'll get to that point once we setlle on the interface.

> works best as
> denoting a type T', whose assignable values are the legal values for type
> T unioned with the value "nil", or "nothing" (as in Haskell). (It
> shouldn't be called "uninitialized", because that would be misleading.
> "nil" is a perfectly valid value for a variable of type T' to take.)
>
This is a possible model.
Another model is that of a container of fixed capacity 1
which can have 0 or 1 elements.

The term uninitalized is unappropriate for the Union model,
but entirely appropriate IMO for the _concept_ of optional values.

> Because "nil" is just another value, operator== can be defined
> straightforwardly. If both are "nil", return true; if exactly one is,
> return false; otherwise the normal comparison value is returned.
>
> operator< could be left undefined, but it is simple enough to arbitrarily
> choose that "nil" is strictly less than every other value. I don't see a
> downside to this, and it would ensure that T' is a strict weak ordering
> whenever T is, which is useful for STL usage.
>
> The operators !=, >, <=, and >= directly follow from definitions of the
> above two operators.
>
Agreed.

Notice that the 0-1-elements container model also allows for a well defined
definition of relational operators.

> Conversion from T' to T is straightforward except when the value of type
> T' is nil. In this case, the developer may want to throw,
> default-construct the value of T, or assert. Template policy choice?
> (Perhaps that's overkill.)
>
As Peter said, default-construct T undermines the whole purpose of optional.
The best is, IMO, to leave it undefined in that case.

>
> One could possibly provide a test for the nil state by declaring an enum
> (in some scope) that defined some (arbitrary) value to "nil", then
> providing an operator== that allowed comparisons on that enum type, to
> allow code such as:
>
> using boost::may_be;
> ...
>
> may_be<int> blah(void) {
>
> may_be<int> x(5); // x is constructed to value 5
> may_be<int> y; // y is default-constructed to value nil
> ...
> if (y != nil) { ... };
> ...
> x = nil;
> ...
> return std::max(x, y); // defined since std::less uses operator<
> };
>
Such a syntax is possible, granted, and we would have it out of the box
with variant<T,nil_t> provided nil_t is a class type.
It is, however, IMO, _too_ cumbersome.

> It is possible, but not necessarily desirable, to include "is_nil()" or
> "is_not_nil()" functions. operator!() already exists in Fernando's code
> as the equivalent to "is_nil()"; a double invocation (e.g. "!!x") would
> be equivalent to "is_not_nil(x)". I suspect it is probably not worth
> fattening the interface for them, but this may be a matter of taste.
>
Agreed.

> (Also, below is a message I had sent to Fernando already, but I suppose it
> might as well be sent to boost also.)
>
--- which I left unresponded... sorry :-)

> Dave
>
>
> ---------- Forwarded message ----------
>
> "Maybe" is a built-in type constructor in Haskell, which AFAIK is the most
> widely used functional programming ("FP") language. It is used to denote
> exactly what your suggested optional<T> is. (Which is why I am
> recommending use of "maybe<T>" or "may_be<T>" instead of optional<T>.)
>
>
> Maybe is defined in Haskell as
>
> data Maybe a = Nothing | Just a deriving (Eq, Ord, Read, Show)
>
> (here "a" is an arbitrary type; "Nothing" is like "nil", "NULL",
> "uninitialized", or whatever you want to call it.)
>
>
> An example in Haskell syntax:
>
> safe_division :: Float -> Float -> Maybe Float
> safe_division x y =
> if y == 0 then Nothing
> else Just (x/y)
>
>
> Consider this Haskell declaration:
> get_maximum_value :: BTree Int -> Maybe Int
>
> The equivalent (free function) declaration in C++ would be:
> may_be<int> get_maximum_value(const BTree<int> &);
>
>
> Yet another function prototype:
>
> get_cached_value :: a -> [(a, b)] -> Maybe b
>
> which can return Nothing if the function does not have "a" as the first
> item of any of the pairs in the list.
>
>
>
> As an example, currently the C++ standard includes
> T & stack<T>::top(), with precondition !(stack.empty()).
>
> Instead, it could be
> may_be<T> & stack<T>::top(); // no precondition required
>
>
> <set> could be improved also, instead of:
> pair<iterator, bool> set::insert(const value_type & x)
>
> we would use
> may_be<iterator> set::insert(const value_type & x)
>
> where the return value is initialized to the place of insertion if x
> was inserted, or is uninitialized if x was not inserted.
>
>
> Of course, it is possible to use variables of type may_be<T>:
>
> int blah(int x) {
>
> may_be<int> y; // default-constructed to uninitialized, right?
> .
> .
> .
> // expressions involving y here are okay instead of invalid.
> .
> .
> .
> };
Those are interesting examples! Thanks.
They can all be paralleled with optional<> whatever the model and interface
we choose.
Which can of shows that the concept is useful.

>
> (The use as an optional function parameter is no doubt what you had in
> mind in the first place, and where you got the "optional" name from.)
>
Actually, the named was coined originally by Peter Dimov;
it used to be called statefull_t<>

Fernando Cacciola


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