Rejecting negative number

Discussion in 'C++' started by JKop, May 24, 2004.

  1. JKop

    JKop Guest

    Take a class like the following:

    class Finger
    {
    public:

    double length;
    }


    I'm writing reusable code and, being dictator, I dictate that "length"
    cannot be negative. The following would be perfect:

    unsigned double length;

    But ofcourse doesn't compile.


    So... I've come up with 3 potential solutions: A1 A2 B .


    A) Create 2 separate member functions, GetLength and SetLength. SetLength
    will reject negative numbers. When supplied with a negative number it will:
    A1) Throw an exception
    A2) Return a false boolean value indicating failure

    B) Just document that the code will have undefined behaviour if length is
    set to a negative number.



    Which would you suggest? Any other suggestions?


    I myself am leaning toward B.


    Thanks


    -JKop
     
    JKop, May 24, 2004
    #1
    1. Advertising

  2. "JKop" <> wrote in message
    news:_uusc.350$...
    > Take a class like the following:
    >
    > class Finger
    > {
    > public:
    >
    > double length;
    > }
    >
    >
    > I'm writing reusable code and, being dictator, I dictate that "length"
    > cannot be negative. The following would be perfect:
    >
    > unsigned double length;
    >
    > But ofcourse doesn't compile.
    >
    >
    > So... I've come up with 3 potential solutions: A1 A2 B .
    >
    >
    > A) Create 2 separate member functions, GetLength and SetLength. SetLength
    > will reject negative numbers. When supplied with a negative number it

    will:
    > A1) Throw an exception
    > A2) Return a false boolean value indicating failure
    >
    > B) Just document that the code will have undefined behaviour if length is
    > set to a negative number.
    >
    >
    >
    > Which would you suggest? Any other suggestions?
    >
    >
    > I myself am leaning toward B.
    >


    A1 without a doubt.

    Also note that A1 is a subset of B, so you could document B but implement A1
    if you really wanted to. When your users complain about the exception, you
    just say 'I told you the behaviour was undefined'.

    john
     
    John Harrison, May 24, 2004
    #2
    1. Advertising

  3. JKop

    JKop Guest

    John Harrison posted:

    > A1 without a doubt.
    >
    > Also note that A1 is a subset of B, so you could document B but
    > implement A1 if you really wanted to. When your users complain about
    > the exception, you just say 'I told you the behaviour was undefined'.



    Thanks for the input.


    I myself think that that would be too kind. "Undefined behaviour" means
    exactly what it says on the tin. It's like saying to a child, "Yes, Go play
    with the matches and the petrol - Just don't come running to _ME_ when
    you've burned yourself". And ofcourse, any responsible parent would say,
    "Don't play with the matches and the petrol!" and then actually physically
    prevent the children from performing such actions.

    But... we're all consenting adults here.


    Although I still haven't made my decision yet.


    All input appreciated.


    Thanks


    -JKop
     
    JKop, May 24, 2004
    #3
  4. JKop

    Petec Guest

    JKop wrote:
    > Take a class like the following:
    >
    > class Finger
    > {
    > public:
    >
    > double length;
    > }
    >
    >
    > I'm writing reusable code and, being dictator, I dictate that "length"
    > cannot be negative. The following would be perfect:
    >
    > unsigned double length;
    >
    > But ofcourse doesn't compile.
    >
    >
    > So... I've come up with 3 potential solutions: A1 A2 B .
    >
    >
    > A) Create 2 separate member functions, GetLength and SetLength.
    > SetLength will reject negative numbers. When supplied with a negative
    > number it will: A1) Throw an exception
    > A2) Return a false boolean value indicating failure
    >
    > B) Just document that the code will have undefined behaviour if
    > length is set to a negative number.
    >
    >
    >
    > Which would you suggest? Any other suggestions?
    >
    >
    > I myself am leaning toward B.
    >
    >
    > Thanks
    >
    >
    > -JKop


    Make a small property template class that allows for range validation, like
    this:

    #include <iostream>
    #include <string>
    #include <cstdlib>
    using namespace std;

    template <class T, class Modify>
    class property
    {
    protected:
    T var;
    Modify mod;
    public:
    property<T, Modify>(const T& init, const Modify& m)
    : mod(m), var(init)
    {}

    operator T()
    {
    return var;
    }

    property& operator =(const T& val)
    {
    if(!mod(val))
    throw invalid_argument("bad property argument.");
    var = val;
    return *this;
    }
    };

    template<class T>
    struct RangeValidationPropModified
    {
    string msg;
    T minval, maxval;
    public:
    RangeValidationPropModified<T>(string m, const T& minv, const T& maxv)
    : msg(m),
    minval(minv),
    maxval(maxv)
    {}

    bool operator() (const T& val)
    {
    if(val >= minval && val <= maxval)
    {
    cout << msg;
    return true;
    }
    else
    return false;
    }
    };

    int main(int argc, char* argv[])
    {
    property<int, RangeValidationPropModified<int> >
    p(0, RangeValidationPropModified<int>("the property is being
    modifed!\n", 0, 100));

    cout << p << endl;
    p = 5;
    cout << p << endl;
    p = 10;
    cout << p << endl;
    try
    {
    p = -1;
    cout << p << endl;
    p = 1000;
    cout << p << endl;
    }
    catch(invalid_argument ex)
    {
    cout << ex.what() << endl;
    }

    system("pause");
    return 0;
    }

    - Pete
     
    Petec, May 24, 2004
    #4
  5. JKop

    Petec Guest

    Petec wrote:
    > JKop wrote:

    <snip>
    >
    > operator T()
    > {
    > return var;
    > }


    Should be:

    operator T&()
    {
    return var;
    }

    To allow operators to be applied.

    >

    <snip>
     
    Petec, May 24, 2004
    #5
  6. JKop

    * Guest

    ?
    "Petec" <> wrote in message
    news:CWusc.8842$...
    > Petec wrote:
    > > JKop wrote:

    > <snip>
    > >
    > > operator T()
    > > {
    > > return var;
    > > }

    >
    > Should be:
    >
    > operator T&()
    > {
    > return var;
    > }
    >
    > To allow operators to be applied.
    >
    > >

    > <snip>
    >
    >
     
    *, May 25, 2004
    #6
  7. JKop

    Petec Guest

    * wrote:
    > ?
    > "Petec" <> wrote in message
    > news:CWusc.8842$...
    >> Petec wrote:
    >>> JKop wrote:

    >> <snip>
    >>>
    >>> operator T()
    >>> {
    >>> return var;
    >>> }

    >>
    >> Should be:
    >>
    >> operator T&()
    >> {
    >> return var;
    >> }
    >>
    >> To allow operators to be applied.
    >>
    >>>

    >> <snip>


    ??

    Please don't top-post, BTW.

    - Pete
     
    Petec, May 25, 2004
    #7
  8. JKop

    Siemel Naran Guest

    "JKop" <> wrote in message
    news:_uusc.350$...

    > unsigned double length;
    >
    > But ofcourse doesn't compile.


    > A) Create 2 separate member functions, GetLength and SetLength. SetLength
    > will reject negative numbers. When supplied with a negative number it

    will:
    > A1) Throw an exception
    > A2) Return a false boolean value indicating failure
    >
    > B) Just document that the code will have undefined behaviour if length is
    > set to a negative number.
    >
    >
    >
    > Which would you suggest? Any other suggestions?


    First choice = B for performance reasons, simplicity of code. The C++
    standard does it all the time (ie. if iterator points to 2 plus end then
    result is undefined, if std::sort compare function does not have strict weak
    ordering then undefined behavior).

    Second choice = A1. As a variation, only if NDEBUG is defined then do we
    throw an exception.

    Third choice = A2.
     
    Siemel Naran, May 25, 2004
    #8
  9. "Petec" <> wrote in message news:<CWusc.8842$>...
    > Petec wrote:
    > > JKop wrote:

    > <snip>
    > >
    > > operator T()
    > > {
    > > return var;
    > > }

    >
    > Should be:
    >
    > operator T&()
    > {
    > return var;
    > }
    >
    > To allow operators to be applied.


    No. If the restriction is that the value should be positive,
    one cannot allow T::eek:perator*=, someonce could pass -1. The same
    applies for operator+=, opertaor/=, and (for positive arguments)
    to operator-=.

    The correct form is operator T() const;, as it won't modify var.

    Regards,
    Michiel Salters
     
    Michiel Salters, May 25, 2004
    #9
  10. JKop

    Petec Guest

    Michiel Salters wrote:
    > "Petec" <> wrote in message
    > news:<CWusc.8842$>...
    >> Petec wrote:
    >>> JKop wrote:

    >> <snip>
    >>>
    >>> operator T()
    >>> {
    >>> return var;
    >>> }

    >>
    >> Should be:
    >>
    >> operator T&()
    >> {
    >> return var;
    >> }
    >>
    >> To allow operators to be applied.

    >
    > No. If the restriction is that the value should be positive,
    > one cannot allow T::eek:perator*=, someonce could pass -1. The same
    > applies for operator+=, opertaor/=, and (for positive arguments)
    > to operator-=.
    >
    > The correct form is operator T() const;, as it won't modify var.


    Ahh, yes, I forgot about that. I'll implement the operators on it and post
    back here...

    - Pete

    >
    > Regards,
    > Michiel Salters
     
    Petec, May 25, 2004
    #10
  11. JKop

    Derek Guest

    > > A) Create 2 separate member functions, GetLength and
    > > SetLength. SetLength will reject negative numbers. When
    > > supplied with a negative number it
    > >
    > > will:
    > >
    > > A1) Throw an exception
    > > A2) Return a false boolean value indicating failure
    > >
    > > B) Just document that the code will have undefined
    > > behaviour if length is set to a negative number.
    > >
    > > Which would you suggest? Any other suggestions?

    >
    > First choice = B for performance reasons, simplicity of
    > code. The C++ standard does it all the time (ie. if
    > iterator points to 2 plus end then result is undefined,
    > if std::sort compare function does not have strict weak
    > ordering then undefined behavior).


    I see your point, but it sounds a bit like premature
    optimization. Not to mention that most of the projects
    I have worked on don't have documentation nearly as
    thorough or complete or up to date as the holy standard
    library. In my experience causing a hard failure is a
    better way to go (exception) -- unless profiling tells
    you there is a performance problem, in which case
    considering the "documented undefined behavior" route
    may be justified.
     
    Derek, May 25, 2004
    #11
  12. JKop wrote:

    > Take a class like the following:
    >
    > class Finger
    > {
    > public:
    >
    > double length;
    > }
    >
    >
    > I'm writing reusable code and, being dictator, I dictate that "length"
    > cannot be negative. The following would be perfect:
    >
    > unsigned double length;
    >
    > But ofcourse doesn't compile.
    >
    >
    > So... I've come up with 3 potential solutions: A1 A2 B .
    >
    >
    > A) Create 2 separate member functions, GetLength and SetLength. SetLength
    > will reject negative numbers. When supplied with a negative number it will:
    > A1) Throw an exception
    > A2) Return a false boolean value indicating failure
    >
    > B) Just document that the code will have undefined behaviour if length is
    > set to a negative number.
    >
    >
    >
    > Which would you suggest? Any other suggestions?
    >
    >
    > I myself am leaning toward B.
    >
    >
    > Thanks
    >
    >
    > -JKop
    >


    From an alternative perspective, define length in terms of the
    smallest unit, then use an unsigned long or unsigned integer.
    For example, one might use millimeters for length:
    class Finger
    {
    unsigned int length; // in millimeters.
    };

    To get more pedantic, one might employ a template property
    for the unit of measurement.


    --
    Thomas Matthews

    C++ newsgroup welcome message:
    http://www.slack.net/~shiva/welcome.txt
    C++ Faq: http://www.parashift.com/c -faq-lite
    C Faq: http://www.eskimo.com/~scs/c-faq/top.html
    alt.comp.lang.learn.c-c++ faq:
    http://www.raos.demon.uk/acllc-c /faq.html
    Other sites:
    http://www.josuttis.com -- C++ STL Library book
     
    Thomas Matthews, May 25, 2004
    #12
  13. JKop

    JKop Guest

    template<class Class>
    Class GeneratePositive(const Class& object)
    {
    return ( (object > 0) ? object : -object );
    }


    -JKop
     
    JKop, May 30, 2004
    #13
  14. JKop

    Siemel Naran Guest

    "JKop" <> wrote in message news:wFluc.911

    > template<class Class>
    > Class GeneratePositive(const Class& object)
    > {
    > return ( (object > 0) ? object : -object );
    > }


    This is a fine solution for a certain problem. But most times I want the
    program to error out when I give in wrong input, not to correct my wrong
    input. This keeps the logic in my own code clear, which helps understanding
    and maintaining the code.

    Though to make it general, should we replace the "0" in object>0 with
    "Class()"? A generic class may not have a conversion from zero as an
    integer to a Class object, namely an implicit constructor Class::Class().
     
    Siemel Naran, Jun 1, 2004
    #14
  15. JKop

    Daniel T. Guest

    In article <_uusc.350$>, JKop <>
    wrote:

    >Take a class like the following:
    >
    >class Finger
    >{
    >public:
    >
    > double length;
    >}
    >
    >
    >I'm writing reusable code and, being dictator, I dictate that "length"
    >cannot be negative. The following would be perfect:
    >
    >unsigned double length;
    >
    >But ofcourse doesn't compile.
    >
    >
    >So... I've come up with 3 potential solutions: A1 A2 B .
    >
    >
    >A) Create 2 separate member functions, GetLength and SetLength. SetLength
    >will reject negative numbers. When supplied with a negative number it will:
    > A1) Throw an exception
    > A2) Return a false boolean value indicating failure
    >
    >B) Just document that the code will have undefined behaviour if length is
    >set to a negative number.
    >
    >
    >
    >Which would you suggest? Any other suggestions?


    As with any other interface question, what would be easer for the
    client? If the client code isn't any different no matter what you
    choose, then choose the one that is easiest to implement (ie 'B'.)


    At the very least, make sure that the behavior is defined in the debug
    version of the program...

    class Finger {
    double _length;
    public:
    double length() { return _length; }
    void length( double l ) { assert( l >= 0 ); _length = l; }
    };

    This is what I would recomend.
     
    Daniel T., Jun 1, 2004
    #15
  16. JKop

    JKop Guest

    Another idea:

    template<class Class> class Unsigned
    {
    private:

    Class object;


    public:

    operator Class(void)
    {
    return object;
    }

    Class& operator=(const Class& in_object)
    {
    return ( object = ( (in_object > 0) ? in_object : -in_object) ) ;
    }
    };


    int main(void)
    {
    Unsigned<double> diameter;

    FunctionThatTakesADouble(diameter);

    return 0;
    }



    One problem though is in specifying arguments to the constructor, and
    accessing member functions and member variables. Then I considered the
    following:




    template<class Class> class Unsigned : public Class
    {
    Class& operator=(const Class& in_object)
    {
    return ( object = ( (in_object > 0) ? in_object : -in_object) ) ;
    }
    };



    But then ofcourse, C++ limits the programmer from inheriting from intrinsic
    types. Also, the operator= of the base class will have to be virtual.


    Any thoughts?


    -JKop
     
    JKop, Jun 2, 2004
    #16
  17. JKop

    JKop Guest

    JKop posted:

    > Also, the operator= of the base class will have to be virtual.



    Wrong about that.


    -JKop
     
    JKop, Jun 5, 2004
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andrew Thompson
    Replies:
    9
    Views:
    473
    Andrew Thompson
    May 6, 2004
  2. Guido van Rossum

    Rejecting the J2 decorators proposal

    Guido van Rossum, Sep 1, 2004, in forum: Python
    Replies:
    2
    Views:
    292
    Nicolas Fleury
    Sep 1, 2004
  3. JohnQ
    Replies:
    0
    Views:
    329
    JohnQ
    Aug 26, 2007
  4. r0g
    Replies:
    1
    Views:
    335
  5. Paul Bibbings
    Replies:
    12
    Views:
    510
    James Kanze
    Jun 22, 2010
Loading...

Share This Page