Rejecting negative number

J

JKop

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
 
J

John Harrison

JKop said:
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
 
J

JKop

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
 
P

Petec

JKop said:
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
 
S

Siemel Naran

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

Michiel Salters

Petec said:
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
 
P

Petec

Michiel said:
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
 
D

Derek

A) Create 2 separate member functions, GetLength and
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.
 
T

Thomas Matthews

JKop said:
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
 
J

JKop

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


-JKop
 
S

Siemel Naran

JKop said:
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().
 
D

Daniel T.

JKop <[email protected]> said:
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.
 
J

JKop

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top