The Artima Developer Community
Sponsored Link

Articles Forum
The Safe Bool Idiom

17 replies on 2 pages. Most recent reply: Oct 13, 2010 12:04 PM by Joe Mucchiello

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 17 replies on 2 pages [ 1 2 | » ]
Chuck Allison

Posts: 63
Nickname: cda
Registered: Feb, 2003

The Safe Bool Idiom Posted: Jul 30, 2004 9:00 PM
Reply to this message Reply
Advertisement
This article shows how to validate C++ objects in a boolean context without the usual harmful side effects.

http://www.artima.com/cppsource/safebool.html


Nathan Holt

Posts: 3
Nickname: nathan2
Registered: Aug, 2004

Re: The Safe Bool Idiom Posted: Aug 2, 2004 9:23 AM
Reply to this message Reply
You mentioned in your article that C++ allows one to delete pointers to const data. What possible reason could the designers have for allowing such an action? Does it allow one to delete const objects as well?

michael toksvig

Posts: 1
Nickname: tox
Registered: Aug, 2004

Re: The Safe Bool Idiom Posted: Aug 2, 2004 9:29 AM
Reply to this message Reply
there appears to be a confusing typo in the article:
class Testable_without_virtual :
public safe_bool {

it should read:
class Testable_without_virtual :
public safe_bool<Testable_without_virtual> {

Chuck Allison

Posts: 63
Nickname: cda
Registered: Feb, 2003

Re: The Safe Bool Idiom Posted: Aug 3, 2004 4:28 PM
Reply to this message Reply
Fixed. Thanks. My fault (not the author's).

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: The Safe Bool Idiom Posted: Aug 3, 2004 8:06 PM
Reply to this message Reply
> This article shows how to validate C++ objects in a
> boolean context without the usual harmful side effects.

Compared to a conversion function to bool, we have avoided the unfortunate overloading issues, and the effects of returning an integral type (making some nonsense constructs legal). We have added the usability that was obscured by operator!, and disabled the potential delete issue with operator void*. Quite impressive! There’s one additional twist that makes the solution complete, and that is to disable comparisons between distinct instances of Testable. With our current implementation, you can write code like this:
  Testable test;
  Testable test2;
  if (test1==test2) {}
  if (test!=test2) {}

Comparisons like the above are not only meaningless; they’re dangerous, because they imply an equivalence relationship that can never exist between different instances of Testable. We need to find a way to disable such nonsensical comparisons.


I, regularly design objects where instance equality and value equality differ. It is not unusual for me to use objects where the internal data dictates equality instead of the instances address or other referenced location.

I found this article to be a great demonstration of how hard the C++ crowd tries to solve problems that just shouldn't be around. This whole boolean comparison thing falls out of the fact that people still think that it saves time, programmer labor and perhaps memory to write
if( ptr ) {
    ...
}

instead of just flat out saying what you mean
if( ptr != NULL ) {
    ...
}

In the Java language design, this whole issue was removed from consideration by demanding an explicit boolean valued expression must be present. Wow, suddenly the problem is completely removed from the programmers radar, and the compiler design is simplified and ...

The other thing of course is the fact that there is a basic Object that has a few very important methods on it. One is the equals(Object) method that makes it even easier to deal with the instance equals verses the value equals issue.

I'm still really appreciating my choice to use Java and not have to deal with such dangerous and burdensome concepts in a computer language.

Greg Hickman

Posts: 1
Nickname: ghackman
Registered: Aug, 2004

Re: The Safe Bool Idiom Posted: Aug 6, 2004 3:16 PM
Reply to this message Reply
Nice article - thank you. One question though: what's wrong with providing

  

bool operator!() const;



along with

  

operator Bool_type() const;



?

Bjorn Karlsson

Posts: 9
Nickname: bfk
Registered: Aug, 2004

Re: The Safe Bool Idiom Posted: Aug 7, 2004 6:16 AM
Reply to this message Reply
Providing operator! is fine -- but not really necessary, as the implicit conversion to a boolean-testable type already adds support for that operator.

Bjorn

Bjorn Karlsson

Posts: 9
Nickname: bfk
Registered: Aug, 2004

Re: The Safe Bool Idiom Posted: Aug 7, 2004 6:50 AM
Reply to this message Reply
> I, regularly design objects where instance equality
> and value equality differ. It is not unusual for
> me to use objects where the internal data dictates
> equality instead of the instances address or other
> referenced location.

Well, sure. That's true for all object-oriented languages (although some languages provide access to lower-level details [such as memory location] and some don't).

> I found this article to be a great demonstration of how
> hard the C++ crowd tries to solve problems that just
> shouldn't be around. This whole boolean comparison thing
> falls out of the fact that people still think that it
> saves time, programmer labor and perhaps memory to write
>
if( ptr ) {
>     ...
> }

> instead of just flat out saying what you mean
>
if( ptr != NULL ) {
>     ...
> }

That's not the end of the story; for example, testing the validity of a stream against NULL is nonsensical, whereas using it as a Boolean type makes perfect sense. (Also, the "C++ crowd" can easily avoid these subtle pitfalls, simply by not using any of the techniques mentioned in the article. Raw pointers can most certainly be tested against NULL without it [although the terser test is also allowed in this fine language!].)

> The other thing of course is the fact that there is a
> basic Object that has a few very important methods on it.
> One is the equals(Object) method that makes it
> t even easier to deal with the instance equals
> verses the value equals issue.

It's not really that hard in C++:

SomeClass sc1,sc2;
// Equality of objects
if (sc1==sc2) {}
// Equality of storage location
if (&sc1==&sc2) {}

> I'm still really appreciating my choice to use Java and
> not have to deal with such dangerous and burdensome
> concepts in a computer language.

For some problems, I agree that there are languages more suitable than C++. On the other hand, the power, expressiveness, beauty, and the language's support for unrestrained creativity are, in my opinion, outstanding virtues of C++ that make me appreciate _my_ choice. As always, your mileage may vary...

Bjorn

Greg Hickman

Posts: 1
Nickname: ghickman
Registered: Aug, 2004

Re: The Safe Bool Idiom Posted: Aug 7, 2004 5:33 PM
Reply to this message Reply
For some reason, Borland C++ Builder 6 has trouble unless I explicitly provide operator !() const. :(

Thanks again,
Greg

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: The Safe Bool Idiom Posted: Aug 15, 2004 6:43 PM
Reply to this message Reply
> That's not the end of the story; for example, testing the
> validity of a stream against NULL is nonsensical, whereas
> using it as a Boolean type makes perfect sense. (Also, the
> "C++ crowd" can easily avoid these subtle pitfalls, simply
> by not using any of the techniques mentioned in the
> article. Raw pointers can most certainly be tested against
> NULL without it [although the terser test is also allowed
> in this fine language!].)

Well, it is a problem in C++ that there are not standard libraries handling I/O streams with all the associated member methods for asking questions like isEof(), availCount() etc. These make much more sense than
if( iostream ) {
   ...
}


which for old C developers would mean is this initialized. It just makes little sense to keep pressing this programming expression given all the history and confusion that persists.

> It's not really that hard in C++:
>
> SomeClass sc1,sc2;
> // Equality of objects
> if (sc1==sc2) {}
> // Equality of storage location
> if (&sc1==&sc2) {}

But, then someone has to remember to define the operator overload for the associated types.

> For some problems, I agree that there are languages more
> suitable than C++. On the other hand, the power,
> expressiveness, beauty, and the language's support for
> unrestrained creativity are, in my opinion, outstanding
> virtues of C++ that make me appreciate _my_ choice. As
> always, your mileage may vary...

For a lot of people, they get to express nonsensical expressions that make sense to them, but which add any real value to the software system that they are constructing.

I'd guess there might be some lazy typing issues, and perhaps some inability to type either due to training or physical issues. I do have sympathy for those that don't like to, or can't type. But, it is an issue that needs to be dealt with for all programming environments.

Kevlin Henney

Posts: 22
Nickname: kevlin
Registered: Apr, 2003

Re: The Safe Bool Idiom Posted: Aug 25, 2004 6:43 AM
Reply to this message Reply
> You mentioned in your article that C++ allows one to
> delete pointers to const data. What possible reason could
> the designers have for allowing such an action? Does it
> allow one to delete const objects as well?

Allowing deletion of const data by definition includes deletion of const objects. The simple reason for allowing it is that disposing of an object is not considered to be a non-const operation on that object, and that there would otherwise be no way of getting rid of const objects.

Even assuming that the underlying object being pointed were not const at creation, the language still allows the expression new const T, which implies that there must be some reasonable way of getting rid of such objects without resorting to const_cast skulduggery.

And then there is the ubiquitous case of being able to declare a local, member or namespace variable const. Such objects have a bounded lifetime and will be properly destroyed at the end of the scope, enclosing object's life or program, so why should dynamically allocated objects be any different?

Ian Crawford

Posts: 3
Nickname: codic
Registered: Aug, 2004

Re: The Safe Bool Idiom Posted: Aug 26, 2004 9:21 PM
Reply to this message Reply
> Well, it is a problem in C++ that there are not standard
> libraries handling I/O streams with all the associated
> member methods for asking questions like isEof(),
> availCount() etc.

Standard C++ provides:
bool basic_ios::eof() const;

A standard POSIX implementation provides:
extern int select (int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
struct timeval *__restrict __timeout);


It may not be pretty, but the complete functionality of select is missing from Java's standard streams. You need to complicate your design with extra threads to mimic it. Also,
InputStream.available()
always returns 0 unless overridden by a derived class which often is not the case.

> But, then someone has to remember to define the operator
> overload for the associated types.

Using the & operator on 2 object instances/references to determine if they refer to the same object requires no operator overloading.

By default, Java's
Object.equals()
only returns true if the 2 objects being compared are, in fact, the same instance of an object. You need to implement all class specific value comparisons yourself.

By default, C++'s operator== compares each data member in a class so you usually get a sensible object value comparison without having to overload anything.

Just the facts.

ian.

Kevlin Henney

Posts: 22
Nickname: kevlin
Registered: Apr, 2003

Re: The Safe Bool Idiom Posted: Aug 27, 2004 1:21 AM
Reply to this message Reply
> By default, Java's Object.equals() only
> returns true if the 2 objects being compared are, in fact,
> the same instance of an object. You need to implement all
> class specific value comparisons yourself.
>
> By default, C++'s operator== compares each
> data member in a class so you usually get a sensible
> object value comparison without having to overload
> anything.
>
> Just the facts.

Or not, as the case might be ;-)

By default, C++ does not provide operator== for user-defined types: that task falls to the programmer.

For equality, Java defaults to identity equality, C++ defaults to nothing, and C# defaults to identity equality for identity-based objects (of class type) and field-by-field comparison for value-based objects (of struct type).

Kevlin

Ian Crawford

Posts: 3
Nickname: codic
Registered: Aug, 2004

Re: The Safe Bool Idiom Posted: Aug 27, 2004 5:34 AM
Reply to this message Reply
> > Just the facts.
>
> Or not, as the case might be ;-)

Haha! Right you are. Confused operator== with operator=. Thanks for straightening me out.

Excuse me while I get this egg off my face.

ian

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: The Safe Bool Idiom Posted: Aug 30, 2004 12:14 PM
Reply to this message Reply
> > Well, it is a problem in C++ that there are not
> standard
> > libraries handling I/O streams with all the associated
> > member methods for asking questions like isEof(),
> > availCount() etc.
>
> Standard C++ provides:
> bool basic_ios::eof() const;

Yes, there is basic_ios, istream, ostream, sstream etc. But I am not enamored by these APIs. They have disconnects and complexities that are just amazing to me to see at such a mature point in the development of this language. Looks like a design by committee where no one was talking (or perhaps even thinking).

> A standard POSIX implementation provides:
> extern int select (int __nfds, fd_set *__restrict
> __readfds,
> fd_set *__restrict __writefds,
> fd_set *__restrict __exceptfds,
> struct timeval *__restrict __timeout);

>
> It may not be pretty, but the complete functionality of
> select is missing from Java's standard
> streams. You need to complicate your design with extra
> threads to mimic it. Also,
>
InputStream.available()
always returns 0
> unless overridden by a derived class which often is not
> the case.

Have you looked at Java since 1.0? The nio package provides access to using native select() or poll() implementations on socket and file streams. There are more enhancements in the works I understand for JDK1.6/6.0

> > But, then someone has to remember to define the
> operator
> > overload for the associated types.
>
> Using the & operator on 2 object
> instances/references to determine if they refer to the
> same object requires no operator overloading.

But, that is more of that confusing syntax stuff that doesn't provide the user with any good sub-conscience glue. Making users type obj1.equals( obj2 ) is not a bad thing either...

> By default, Java's
Object.equals()
only
> returns true if the 2 objects being compared are, in fact,
> the same instance of an object. You need to implement all
> class specific value comparisons yourself.

By default == and .equals() are equivalent for any class that does not override .equals(). In applications where it make sense, you can redefine .equals() to be value based instead of instance based.

> By default, C++'s operator== compares each
> data member in a class so you usually get a sensible
> object value comparison without having to overload
> anything.

I believe this was pointed out to be in error. Would be interesting to see how that would be implemented without == being assigned to a member method to begin with.

Flat View: This topic has 17 replies on 2 pages [ 1  2 | » ]
Topic: Where Do You Want to Be in Five Years? Previous Topic   Next Topic Topic: What's New in Scala 2.8: Named and Default Parameters

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use