Article Discussion
The Safe Bool Idiom
Summary: Learn how to validate objects in a boolean context without the usual harmful side effects.
17 posts.
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: October 13, 2010 11:04 AM by Joe
    Chuck
     
    Posts: 32 / Nickname: cda / Registered: February 11, 2003 0:06 PM
    The Safe Bool Idiom
    July 30, 2004 8:00 PM      
    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
    • michael
       
      Posts: 1 / Nickname: tox / Registered: August 2, 2004 4:19 AM
      Re: The Safe Bool Idiom
      August 2, 2004 8:29 AM      
      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
         
        Posts: 32 / Nickname: cda / Registered: February 11, 2003 0:06 PM
        Re: The Safe Bool Idiom
        August 3, 2004 3:28 PM      
        Fixed. Thanks. My fault (not the author's).
    • Greg
       
      Posts: 1 / Nickname: ghackman / Registered: August 6, 2004 9:48 AM
      Re: The Safe Bool Idiom
      August 6, 2004 2:16 PM      
      Nice article - thank you. One question though: what's wrong with providing

        

      bool operator!() const;



      along with

        

      operator Bool_type() const;



      ?
      • Bjorn
         
        Posts: 9 / Nickname: bfk / Registered: August 4, 2004 9:28 AM
        Re: The Safe Bool Idiom
        August 7, 2004 5:16 AM      
        Providing operator! is fine -- but not really necessary, as the implicit conversion to a boolean-testable type already adds support for that operator.

        Bjorn
        • Greg
           
          Posts: 1 / Nickname: ghickman / Registered: August 6, 2004 10:27 AM
          Re: The Safe Bool Idiom
          August 7, 2004 4:33 PM      
          For some reason, Borland C++ Builder 6 has trouble unless I explicitly provide operator !() const. :(

          Thanks again,
          Greg
    • Nathan
       
      Posts: 3 / Nickname: nathan2 / Registered: August 2, 2004 3:38 AM
      Re: The Safe Bool Idiom
      August 2, 2004 8:23 AM      
      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?
      • Kevlin
         
        Posts: 2 / Nickname: kevlin / Registered: April 25, 2003 3:37 AM
        Re: The Safe Bool Idiom
        August 25, 2004 5:43 AM      
        > 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?
    • Gregg
       
      Posts: 28 / Nickname: greggwon / Registered: April 6, 2003 1:36 PM
      Re: The Safe Bool Idiom
      August 3, 2004 7:06 PM      
      > 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.
      • Bjorn
         
        Posts: 9 / Nickname: bfk / Registered: August 4, 2004 9:28 AM
        Re: The Safe Bool Idiom
        August 7, 2004 5:50 AM      
        > 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
        • Gregg
           
          Posts: 28 / Nickname: greggwon / Registered: April 6, 2003 1:36 PM
          Re: The Safe Bool Idiom
          August 15, 2004 5:43 PM      
          > 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.
          • Ian
             
            Posts: 3 / Nickname: codic / Registered: August 26, 2004 3:49 PM
            Re: The Safe Bool Idiom
            August 26, 2004 8:21 PM      
            > 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
               
              Posts: 2 / Nickname: kevlin / Registered: April 25, 2003 3:37 AM
              Re: The Safe Bool Idiom
              August 27, 2004 0:21 AM      
              > 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
                 
                Posts: 3 / Nickname: codic / Registered: August 26, 2004 3:49 PM
                Re: The Safe Bool Idiom
                August 27, 2004 4:34 AM      
                > > 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
               
              Posts: 28 / Nickname: greggwon / Registered: April 6, 2003 1:36 PM
              Re: The Safe Bool Idiom
              August 30, 2004 11:14 AM      
              > > 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.
              • Ian
                 
                Posts: 3 / Nickname: codic / Registered: August 26, 2004 3:49 PM
                Re: The Safe Bool Idiom
                September 3, 2004 5:54 PM      
                > 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.

                Hey, lookie there! I googled for this a couple months ago and found nothing (except a few people saying it couldn't be done). Must have been using crappy search criteria.

                > 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...

                I wouldn't call the "address of" operator confusing, but it's all a matter of opinion.

                > Would be
                > interesting to see how that would be implemented without
                > == being assigned to a member method to begin with.

                The compiler writers have managed to do it with implicitly defined operator= and copy constructors. I don't think it's too much of a stretch to apply similar member traversal logic to equality comparisons, but aparently some one did. Perhaps the answer lies in the ARM.



                Well, shame on me for not knowing my tools. I obviously don't know either language well enough to effectively argue the finer points of either one in a public forum.

                But I do know that you use the right tool for the right job. Sometimes the right tool is C++ (like it or not), and articles like this make better programmers out of all of us.

                ian.
                • Victor
                   
                  Posts: 1 / Nickname: sekmu / Registered: March 30, 2009 1:59 PM
                  Re: The Safe Bool Idiom
                  March 30, 2009 7:19 PM      
                  A word of warning, and a question for if anyone has encountered and/or has a solution for this issue (other than the obvious "don't allow this code").

                  If you (already) have an explicit conversion to a pointer type other than bool_type, the compiler may very well choose the non-bool_type, resulting in unexpected behavior.

                  example crashy:

                  class Testable
                  {
                  private:
                  Thing *mData;

                  public:
                  typedef void (xOGModelRefPtr::*bool_type)() const;
                  void type_does_not_support_comparisons() const {}
                  operator bool_type() const
                  {
                  return (mData && mData->IsValid()) ? Testable::type_does_not_support_comparisons : NULL;
                  }

                  Testable() : mData(NULL) {}
                  operator Thing*() const { return mData->mPtr; }
                  };

                  void fn(Thing *);
                  void main()
                  {
                  Testable t;
                  if(t) // crash on access of null mData->
                  fn(t);
                  }

                • Joe
                   
                  Posts: 1 / Nickname: joem / Registered: October 13, 2010 6:02 AM
                  Re: The Safe Bool Idiom
                  October 13, 2010 11:04 AM      
                  Is this code copyright restricted? Is there a license for reuse of this code?