Article Discussion
Built-in Type Safety?
Summary: C++ is a statically typed language but its type system is not bulletproof. This article reveals some all-too-common type glitches and how to fix them.
14 posts.
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: January 16, 2006 4:05 AM by Thomas
    Chuck
     
    Posts: 32 / Nickname: cda / Registered: February 11, 2003 0:06 PM
    Built-in Type Safety?
    June 25, 2005 2:30 PM      
    C++ is a statically typed language but its type system is not bulletproof. This article reveals some all-too-common type glitches and how to fix them.

    http://www.artima.com/cppsource/typesafety.html
    • Bob
       
      Posts: 3 / Nickname: hiredgoon / Registered: April 27, 2005 1:18 PM
      Re: Built-in Type Safety?
      June 25, 2005 9:21 PM      
      Thanks for an interesting article. Rules for signed arithmetic are actually pretty complicated, which is apparently one of the reasons it was left out of Java. I still like them though for things like array indices and length as you only need to test upper bounds.

      I've never seen The Named Parameter Idiom before. It's an interesting idea that looks good (returning a this reference reminds me operator overloading) but since you can't force the caller to call each parameter it might not make sense for classes that maintain an invariant, eg if you want your rectangles to have non-zero area.
    • Matt
       
      Posts: 62 / Nickname: matt / Registered: February 6, 2002 7:27 AM
      Re: Built-in Type Safety?
      June 26, 2005 9:36 PM      
      Looks problem number 2 has another bug: the hard-coded 256 and 288 values should be 255 and 287 respectively (except when used as width and height). It looks to me like the program will be trying to write off the screen on the right and bottom by a pixel.

      I've always liked the idea of passing a structure when many parameters are required, because in addition to reducing the odds of mistakes when it is written, it also produces self-documenting code. The boost named parameters stuff is also cool.

      There are other points of weakness in the C/C++ type system. Enumerated values and booleans get mistaken for integral types all too easily. And what's worse, in a mixed language system, such as the one deployed on the Talk-To-Me, they can change size and alignment when passing from C to C++.
      Why do people still do this? What is the value? Are there really still some places where you have have a C compiler, but no C++ compiler? Maybe that is the case with this Talk-To-Me gadget?
      • Thomas
         
        Posts: 13 / Nickname: tag / Registered: November 16, 2004 7:25 PM
        Re: Built-in Type Safety?
        June 27, 2005 0:44 AM      
        > Looks problem number 2 has another bug: the hard-coded 256
        > and 288 values should be 255 and 287 respectively (except
        > when used as width and height). It looks to me like the
        > program will be trying to write off the screen on the
        > right and bottom by a pixel.

        Good point -- this may indeed be a source of confusion. However, the convention used here is the usual C/C++ one of one-past-the-end values. That is to say, a Rectangle empty(0, 0, 0, 0); contains zero pixels and Rectangle tiny(0, 0, 1, 1); contains just one pixel.

        > I've always liked the idea of passing a structure when
        > many parameters are required, because in addition to
        > reducing the odds of mistakes when it is written, it also
        > produces self-documenting code. The boost named
        > parameters stuff is also cool.

        It's certainly cool. I haven't tried it in anger, so I can't give it an unreserved recommendation. There was some interesting discussion on the Boost reflector when it faced the Boost peer review process.

        > There are other points of weakness in the C/C++ type
        > system. Enumerated values and booleans get mistaken for
        > integral types all too easily. And what's worse, in a
        > mixed language system, such as the one deployed on the
        > Talk-To-Me, they can change size and alignment when
        > passing from C to C++.

        > Why do people still do this? What is the value? Are
        > there really still some places where you have have a C
        > compiler, but no C++ compiler? Maybe that is the case
        > with this Talk-To-Me gadget?

        Sometimes third party libraries come pre-built. Sometimes they're delivered as source, but with a fiddly build system which is hard-wired to C. And sometimes they don't get through a C++ compiler.

        I very much take your point here though: stick to a C++ compiler and avoid this problem.
    • Matt
       
      Posts: 62 / Nickname: matt / Registered: February 6, 2002 7:27 AM
      Re: Built-in Type Safety?
      June 26, 2005 9:01 PM      
      Um, am I missing something obvious? It seems to me that problem 1 was extremely contrived. If the check had been implemented correctly and more clearly in the first place, none of this trouble would arise:

      bool signalsDifferent(Signal s1, Signal s2, int tol)
      {
         return abs( s1 - s2 ) > tol;
      }
      


      Or was this the usual C++ coding gaffe of trying to save a couple of nanoseconds by not calling abs()?
      • Thomas
         
        Posts: 13 / Nickname: tag / Registered: November 16, 2004 7:25 PM
        Re: Built-in Type Safety?
        June 27, 2005 0:49 AM      
        > Um, am I missing something obvious? It seems to me that
        > problem 1 was extremely contrived. If the check had been
        > implemented correctly and more clearly in the first place,
        > none of this trouble would arise:
        >
        >
        bool signalsDifferent(Signal s1, Signal s2, int
        > tol)
        > {
        >    return abs( s1 - s2 ) > tol;
        > }
        > 
        


        You're right, we should use the standard library as far as possible. I can assure you, though, that the example is not contrived. You really will find code like the code I presented in the article without having to look too hard.

        > Or was this the usual C++ coding gaffe of trying to save a
        > couple of nanoseconds by not calling abs()?
    • Alex
       
      Posts: 4 / Nickname: alblue / Registered: April 14, 2003 0:07 AM
      Re: Built-in Type Safety?
      June 26, 2005 0:54 AM      
      The top-left/bottom-right combination is only 'the most sensible' because of what you've been used to. If you were a native speaker/reader/writer of other languages, such as Hebrew, Chinese or Arabic, you might have a different idea of what is sensible. Of course, it probably makes sense to tie it in with how the hardware addresses the screen :-)
      • Thomas
         
        Posts: 13 / Nickname: tag / Registered: November 16, 2004 7:25 PM
        Re: Built-in Type Safety?
        June 27, 2005 1:15 AM      
        > The top-left/bottom-right combination is only 'the most
        > sensible' because of what you've been used to. If you were
        > a native speaker/reader/writer of other languages, such as
        > Hebrew, Chinese or Arabic, you might have a different idea
        > of what is sensible.

        Right. And as stated in the article, we're in a situtation where there's no single established convention.

        > Of course, it probably makes sense to
        > tie it in with how the hardware addresses the screen :-)

        This is something I failed to mention. A system of any size may well have a few different rectangle implementations: the C struct used in the display driver, the C++ rectangle class in the middleware graphics routines, another C++ rectangle class which accidentally got re-invented. If these rectangles all use different conventions we may hit problems converting between them.
    • Harrison
       
      Posts: 7 / Nickname: hxa7241 / Registered: April 10, 2005 7:41 AM
      Re: Built-in Type Safety?
      June 26, 2005 10:54 AM      
      There is a Scott Meyers article pertinent to this: "Signed and unsigned types in interfaces", C++ Report, September 1995. http://aristeia.com/Papers/C++ReportColumns/sep95.pdf. I disagreed at first, then I saw sense. And it works -- I have avoided all these problems since. Just always use signed integer types in all situations (unsigned only for bit-fiddling and suiting libraries). Representing positive-only values as unsigned is well intentioned, but the implicit conversions of builtin types destroy the intended constraint.

      Taligent's guide http://www.amazon.com/exec/obidos/ASIN/0201408880 entreats use of typedefs for builtin types. But, since a typedef is not really a type, it makes the conversion behaviour implicit, and making things implicit is a bad idea generally. This is an example where it has contributed to failure. So just do not use typedefs for builtins.

      Maths, with cartesian graphs, sets a standard of x then y. Everyone learns that. It really should always be followed when handling coordinates in two dimensions. It is annoying that (top,left)(bottom,right) seems to have become popular, for no good reason.
      • Kristian
         
        Posts: 4 / Nickname: chryler / Registered: December 2, 2003 5:09 AM
        Re: Built-in Type Safety?
        June 27, 2005 6:17 AM      
        I resort to signed ints everywhere as well but I do find it tedious to work with *::size_type in the standard library. Why on Earth did they use unsigned types?
    • Jeff
       
      Posts: 1 / Nickname: azswdude / Registered: July 2, 2005 1:23 PM
      Re: Built-in Type Safety?
      July 2, 2005 6:17 PM      
      I have a few thoughts on this subject. First, I really like the idea of using small types to enforce these sort of constraints. I believe it enhances code clarity and can be done such that there is minimal to no runtime impact. Boost date-time uses the concept to ensure that when someone attempts to construct a date or time they do something 'silly'. For example:


      date(2005, Jun, 50); //oops causes bad_day exception


      This is achieved using a template called constrained_int that takes traits including a valid range and exception policy. A small wrapper type called greg_day uses constrained_int do the work in a couple typedefs. You can see the code here:


      http://cvs.sourceforge.net/viewcvs.py/boost/boost/boost/date_time/gregorian/greg_day.hpp?rev=1.5&view=auto
      http://cvs.sourceforge.net/viewcvs.py/boost/boost/boost/date_time/constrained_value.hpp?rev=1.4&view=auto

      Christopher Diggins has improved upon this and written it up in a couple places:

      http://www.artima.com/weblogs/viewpostP.jsp?thread=79470

      So challenge #1 is for someone that wants to become a Boost author to come forward, pull these ideas together and make an official Boost library out of these ideas :-)

      Some additional thoughts on the article. Seems to me that the full screen issue there are a couple simple options not considered.

      1) Provide a direct constructor with handy options:


      class rectangle {
      public:
      enum SPECIAL_TYPES { FULL_SCREEN, NULL };
      rectangle(SPECIAL_TYPES = NULL)
      {
      if (FULL_SCREEN) {...//set here
      }


      2) Provide a factory function to create a full screen


      class rectangle {
      public:
      static rectangle make_full_screen() {...


      Note this can be external to the original class if need be.

      3) Create a derived type that is a constructor only


      class full_screen_rectangle : public rectangle {
      public:
      full_screen_rectangle() :
      rectangle(...set the values here...)
      {}


      Of course, in theory, since the base class probably doesn't have a virtual destructor this last option is technically not 'recommended practice'. However, I believe in practice it is in fact safe and portable to all compilers since there is nothing to destroy in the subclass. And, of course, full_screen_rectangle can be used anywhere rectangle is used.

      Note that in all cases the building of a small lightweight type has he nice benefit of enhancing the code readability and encapsulating the 'knowledge' of what 'full screen' means in a single location in the code.

      To sum up on the rectangle case, I'd be very unlikely to code it with 4 primative values. The 'point' and some of the other solutions in the article would be better than the initial design.
    • indranil
       
      Posts: 8 / Nickname: indranil / Registered: November 7, 2004 8:29 AM
      Re: Built-in Type Safety?
      June 26, 2005 7:11 AM      
      I really like this article! Nice concrete examples of how modern C++ idioms can help eliminate common programming errors.

      Techniques such as constrained values and Boost Parameters just cant be done in languages like Java and C#. But a lot of the these problems are just as possible in those languages.
      • Thomas
         
        Posts: 13 / Nickname: tag / Registered: November 16, 2004 7:25 PM
        Re: Built-in Type Safety?
        August 15, 2005 1:52 AM      
        A quick update. This article, dated June 2005, references the up-and-coming "Boost Parameters Library" which at the time had yet to be formally released.

        Boost 1.33.0 has now been now released and the "Boost Parameter Library" is indeed there:

        http://boost.org/libs/parameter/doc/html/index.html
    • Cleo
       
      Posts: 6 / Nickname: vorlath / Registered: December 16, 2005 1:35 AM
      Re: Built-in Type Safety?
      December 29, 2005 6:10 PM      
      I actually like unsigned types. Without them, you waste a lot of memory for unbounded integers that can grow beyond the normal 32 or 64 bits (or rather beyond the size allowed by the compiler). You need unsigned ints to represent larger signed ints. This results in infinite amounts of frustration with Java where you waste twice as much memory for nothing. They're also necessary if you want to right shift without setting the high bit if you're manipulating bits and not numbers per se.

      Overall, I found all the examples to be lack of experience or knowledge. Yes, they happen to the best of us and there should be better ways. I don't think there's any argument there. But if you use a non-saturated integer type, you have to expect some problems if you don't check your math.

      When I saw the width, height example, I was thinking that's got to be reversal of x and y. Happens all the time to anyone that's done any kind of graphics.

      I didn't see anything in this article that isn't part of any normal programmer's learning curve. BTW, the type safety you mention is a little odd. In C++/C, the type mechanism is only there to help you use the same type. What you do with those types is up to you. An int or unsigned int is not a saturated type or bounded in any way. That's your choice to use them and so you have to accept the errors you encounter if you don't use something safer.

      Nice examples and good for any learning programmer. But if you don't watch what the properties of the types you use are, then there's nothing any language or technique is gonna be able to do to help you.
      • Thomas
         
        Posts: 13 / Nickname: tag / Registered: November 16, 2004 7:25 PM
        Re: Built-in Type Safety?
        January 16, 2006 4:05 AM      
        > I actually like unsigned types. Without them, you waste a
        > lot of memory for unbounded integers that can grow beyond
        > the normal 32 or 64 bits (or rather beyond the size
        > allowed by the compiler). You need unsigned ints to
        > represent larger signed ints.

        If you really need that most significant bit of an unsigned number, you're dangerously close to wrapping.

        > This results in infinite
        > amounts of frustration with Java where you waste twice as
        > much memory for nothing.

        On the other hand, a guarantee over size and a guaranteed 8 byte long can be of use. For example, you don't really need to worry about timer wrap in Java code. Not in the lifetime of this planet, anyway.

        A 4 byte unsigned milliseconds timer wraps quite often.

        > They're also necessary if you
        > want to right shift without setting the high bit if you're
        > manipulating bits and not numbers per se.

        I hope its clear that bit shifting should always be done on unsigned values.

        Scott Meyers wrote an interesting article promoting the use of signed ints in interfaces.

        http://www.aristeia.com/publications_frames.html
        "Signed and Unsigned Types in Interfaces"

        > Overall, I found all the examples to be lack of experience
        > or knowledge.

        Nonetheless, I hope some readers may benefit. FWIW, these are true stories, and experienced programmers really were caught out.

        > Yes, they happen to the best of us and
        > there should be better ways. I don't think there's any
        > argument there. But if you use a non-saturated integer
        > type, you have to expect some problems if you don't check
        > your math.
        >
        > When I saw the width, height example, I was thinking
        > that's got to be reversal of x and y. Happens all the
        > time to anyone that's done any kind of graphics.

        Yes, I agree. My point is that what appeared to be a type-related problem did not get caught by the compiler. Only careful system testing caught the error. There are techniques enabling you to lean harder on the type system and catch this problem.

        > I didn't see anything in this article that isn't part of
        > any normal programmer's learning curve. BTW, the type
        > safety you mention is a little odd. In C++/C, the type
        > mechanism is only there to help you use the same type.
        > What you do with those types is up to you. An int or
        > r unsigned int is not a saturated type or bounded in any
        > way. That's your choice to use them and so you have to
        > accept the errors you encounter if you don't use something
        > safer.
        >
        > Nice examples and good for any learning programmer.

        Thanks.

        > But
        > if you don't watch what the properties of the types you
        > use are, then there's nothing any language or technique is
        > gonna be able to do to help you.

        Testing can still help.