Boost logo

Boost :

From: Brian McNamara (lorgon_at_[hidden])
Date: 2003-08-31 12:35:25


So I completely disagree that optionals should mix the interfaces of
optional and the wrapped object into one. I think there should be an
explicit unwrapping operation. But this is just my opinion, based on no
practical evidence/experience, and I'm sure there are trade-offs either
way. I'll explain the crux of my own reasoning below.

On Sun, Aug 31, 2003 at 11:59:42PM +0800, Joel de Guzman wrote:
> It's really strange (and hard to explain) that you have to dereference
> optional<B>. Example:
>
> F(tuple<A, optional<B>, C> args)
> {
> A a = get<1>(args);
> B b = *get<2>(args); // strange!
> C c = get<3>(args);
> }

I don't think it's strange at all; an optional<B> is not a B!

> Not only is it strange, it complexifies the code a lot when the code is
> automatically generated by some meta-program. Example:
>
> template <class A, class B, class C>
> F(tuple<A, B, C> args)
> {
> A a = get<1>(args);
> B b = get<2>(args);
> C c = get<3>(args);
> }
>
> Whoops, have to do a special case IFF B is an optional!

Well, no. B==optional<Bprime> via template unification, right?
If you want to do something with a Bprime, then yes, you have to
special-case it, as you should.

Here's a (contrived) example of how the implicit conversion breaks
generic code:

   template <class Container>
   void contrived( Container& c ) {
      c.begin();
   }
   ...
   vector<int> v;
   contrived(v); // fine
   optional<vector<int> > ov( v );
   contrived(ov); // fails

The point is that optional<T> is not a T, and most notably, a template
function will never perform the coercion. Replace the lines like
   B b = get<2>(args);
in your example with real calls to, e.g.
   do_something( get<2>(args) )
and do_something() is likely to fail if it's a template function
(expecting a T and not an optional<T>).

As another example, FC++ lists support conversion-to-bool as a test for
NIL:
   fcpp::list<int> l = NIL;
   if( l ) // if l not empty
      cout << head(l); // print first element
Clearly if 'l' were an optional, the "if" test would have a different
meaning. I know you've been supporting a separate way to do the test
(with "==none"), but I think that's completely arbitrary. The two
issues are both really the same issue, in my mind.
   

> Of all the types involved in the passing of arguments to the semantic
> actions, the optional doesn't fit nicely because it is the only one
> that has mixed value/pointer semantics. I am tempted to not use
> optional<T> because of this and instead use variant<T, none>,
> but I hate to miss the performance advantage of optional vs.
> variant<T, none>.

I have not used variant and know little about it, but I imagine you have
to explicitly tell a variant "which type" you expect to get out of it.
I think the same is true of optional; the call to operator*() (or
whatever) says "I want the T type" (rather than the 'none').

My two cents. Again let me stress I'm arguing based on no practical
experience working with any of these datatypes.

-- 
-Brian McNamara (lorgon_at_[hidden])

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