--On Sunday, August 31, 2003 1:35 PM -0400 Brian McNamara <[EMAIL PROTECTED]> wrote:
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!
That doesn't make it a pointer to B! I think the above code is strange for two independent reasons. First, as I said before I think that though pointers may model possibly uninitialized variables, the converse does not always hold. Second, I think that it might be useful to treat variables and possibly uninitialized variables uniformly as much as possible (except where it overly compromises safety). I hold strongly to the first argument, though I admit that the second one may not stand up in the end.
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
There's conversion-to-bool again. I still wonder whether dispensing with this would open the door to implicit conversions.
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.
I'm still not clear as to why.
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 ([EMAIL PROTECTED])
- Mat _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost