Boost logo

Boost :

From: Brian McNamara (lorgon_at_[hidden])
Date: 2003-08-30 22:16:28

On Sun, Aug 31, 2003 at 09:58:45AM +0800, Joel de Guzman wrote:
> Fernando Cacciola <fcacciola_at_[hidden]> wrote:
> > Hi Mat,
> >
> > Thanks for the input.
> >
> > optional<> is now out on the field and it is the only utility of its
> > kind I've ever seen in C++, at least in real use. This has the
> > drawback that there is very little experience with it. Therefore, in
> There's a lot of experience with it in other languages. Why not
> leverage that? Haskell::Maybe for instance.

I feel like Maybe works more smoothly in Haskell than in C++, but I
haven't ever really tried to nail down the reasons why. This thread has
me thinking about it more, though, so I'll share some general thoughts
(as well as some suggestions for "optional" at the end).

Two issues spring to mind immediately: pattern matching and monads.

Pattern matching:
Haskell's Maybe is a type constructor, and thus the value constructors
Just and Nothing can be used in pattern matches. Pattern
matching provides a common way to do the "test" and the "unwrap"
steps. Code like

   optional<int> o;
   if( o )
      do_something( *o );

in C++ sometimes takes a form like

   o :: Maybe int
   case o of Just x -> doSomething x
             Nothing -> maybeDoOther

in Haskell. Since this form of using pattern matching to "case-ify" and
deconstruct a datatype is a standard idiom in Haskell, nothing special
needs to be done for Maybe.

In addition, Maybe forms a monad, which means that you can use
do-notation to string together computations involving Maybes. Code like

   optional<int> x, y, z, result;
   if( x ) {
      y = foo( *x );
      if( y ) {
         z = bar( *x, *y );
         if( z )
            result = baz( *x, *y, *z );
            result.reset(); // being more explicit than I have to be

can be written as

   x, y, z, result :: Maybe int
   do x <- x
      y <- foo x
      z <- bar x y
      result <- baz x y z
      return result

in Haskell, which uses the Monad's bind operation to sugarize over all
the if-then-else plumbing to push Nothings all the way through the
computation. In FC++, we have monad comprehensions, so it could be
written as just

   maybe<int> x;
   fcomp_m<maybe_m>()[ baz[X,Y,Z] | X <= x,
                                    Y <= foo[X],
                                    Z <= bar[X,Y] ]
Comprehensions are unlikely to be used much in normal C++ code, though.

In any case, I suppose my point with both of those issues is that
Haskell already has some kind of standard/idiomatic way to sugarize over
the details of dealing with Maybes. I don't think we have anything
equivalent in C++, so it's not clear to me what we can learn from
Haskell when trying to design the interface for optional in C++.

Offhand, the "pointer interface" for reading the value of an optional
seems good to me. Being able to say

   optional<int> x;
   if( x ) foo( *x );

seems like a natural way to "sugarize" this in C++.

As for the constructors, why not have a separate function for
initializing optionals, a la Just/Nothing in Haskell? I am imagining
something like this:

   template <class T>
   class optional {
      optional(); // or maybe public, depending on preference
      optional( const T& ); // private
      optional( const optional& ); // still copyable,
      optional& operator=( const optional& ); // assignable
      ... operator bool ... operator*
   template <class T>
   optional<T> just( const T& ); // the constructor (a friend)

Then you no longer have the issue of

   optional<int> x(3);
   int r = *x;
   optional<int> y = 4;
   r = *y;

looking "funny" or "unbalanced", because now it's

   optional<int> x( just(3) );
   int r = *x;
   optional<int> y = just(4);
   r = *y;

and the "just" balances out the "*", in a way.

(This is similar to what we do with maybe<T> in FC++, though we don't
have the op-bool/op-* sugar for reading maybes. In FC++, the constant
NOTHING can also be used to initialize an "empty" maybe.)

-Brian McNamara (lorgon_at_[hidden])

Boost list run by bdawes at, gregod at, cpdaniel at, john at