Boost logo

Boost :

From: William E. Kempf (wekempf_at_[hidden])
Date: 2002-12-16 11:47:26

Fernando Cacciola said:
> "William E. Kempf" <wekempf_at_[hidden]> escribió en el mensaje
>> Fernando Cacciola said:
>> [snip William's comments about the interface with operator T&]
> I agree with your comments about the interface with operator T&.
> I show it in the post, actually, because I wanted to follow again the
> line of reasonging I had in the past.
> That interface didn't had safe_bool but it was a bad choice anyway.
>> > Safe_bool will allow the familiar idioms:
>> >
>> > if ( opt )
>> > if ( !opt )
>> > if ( opt == 0 )
>> > if ( opt != 0 )
>> >
>> > The first form, which is probably the most used, comunicates exactly
>> what it means.
>> > But the second form, using operator ==, appears to me confusing for
>> value-semantic objects because a comparison against 0 as indication
>> of uninitialization is typical of pointers but not of containers.
>> Some would consider it confusing, and they'd just avoid using it.
>> Others won't, and I see no reason to prevent them from using this.
> Actually, *I* wouldn't find it that much confusing either.
> I was thinking of it from the POV of those who see the pointer-like
> interface confusing: I argue that if we want to have 'ref()'
> instead of 'opertor*()' because the later makes optional look like
> something it isn't; then safe_bool would confuse just the same,
> so either we keep safe_bool and the rest of the pointer-like interface
> (because safe_bool is itself a pointer-like interface) or we drop both.

I don't agree with this reasoning. The safe-bool concept is used in a lot
of situations: testing for iostream validity, testing the lock state on
scoped locks, testing for NULL pointer values in smart pointers, etc. I
don't think the presence of safe-bool here is any more confusing than it's
use in any of these cases (or the hundreds of others I didn't list).
There's no one reason for providing a bool conversion, other than to make
a frequent test easier to type (and in some cases, as Mr. Dimov points
out, to actually code as well).

>> > No container-like object that I know of uses that idiom to indicate
>> emptyness() so I believe it would we wrong to have it in this sort
>> of interface
>> >
>> > As a conclusion, I agree that it is possible to model optional<>
>> entirely as a 1-element-sequence provided that its
>> > interface uses explicit member funcions for both value access and
>> emptyness testing.
>> I can live with that, but I honestly see no reason to avoid the
>> safe-bool.
> I don't see reason either, but along the same argument I don't see
> reason to drop operator*() and ->()

The only reason from my POV is that the comparison operators become
completely non-intuitive to a very large audience with this operators
present. Personally, I agree with Mr. Abrahams that this is something
that can be learned, and there's compelling reasons to retain all of this
(i.e. pointer semantics, deep const, and deep comparison) even if it's
non-intuitive at first. I was only suggesting the alternative because it
seemed most people were stuck on the counter-intuitiveness of comparison
operations (which I think are essential). IOW, I can live with the smart
pointer design with deep comparisons.

> My point is that safe_bool is a pointer-like interface; you use it to
> write code like: if ( p ) or if ( p == 0 ); which is the behaviour of a
> pointer (notice that it is not comparing the optional value against 0
> but its initialization state); so if this interface makes sense, then
> the rest of the pointer-like interface makes sense too.

No, it's not a "pointer-like" interface. Again, look at the many other
use cases that are not "pointer-like" in existence today.

>> So, just to keep pointer-like operations you're going to make the
>> interface difficult to use for many valid use cases?
> I don't know yet. This is a though call.


> Having both well defined relational operators and a pointer like
> interface _might_ confuse people, but I don't know at to what extent.
> if you see: if ( opt0 == opt1 ), out of context, you expect this to do
> _exactly_ 0what it would actually do with a value-based definition of
> relops.
> The only problem is if you see this _and_ you think opt _is_ a pointer,
> so you think it is not comparing optional values.
> Therefore, we can just _require_ users to keep in mind what optional
> really is and have both relops and a pointer-like interface.

Sounds good to me (and I think several others), but there are people who
won't be happy with this.

> Some people, mostly _me_, argued that this is not a good idea
> because code would change meaning if optional<> is replaced
> by a pointer.

But it's going to change in any event, because optional<> _isn't_ a pointer.

> However, after I realized that not being optional a pointer,
> thinking it is would get you in trouble no matter how the interface
> tries to prevent it. I'm not so sure anymore that forbiding a
> useful-in-itself operation in the name of safety is really worth it.
> ...BTW, this is what you have been telling me from the beginning,
> isn't it :-)

Yep. :)

> But, if I add deep relops, the problem remains, only that with
> a different face: optional is not a pointer even though it looks
> like it. If optional is used in generic code _and_ you use
> comparisons directly (without *), the semantics will be
> inconsistents.

But in generic code you must follow the semantics of the concept, and
optional<> isn't useable when a SmartPointer concept is required. Define
the concept well enough, and optional<> becomes useful in generic code.

> But I can choose to _prevent_ users about this mistake on the
> documentation.
> This would bring the most useful model if used properly.

I think so.

William E. Kempf

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