Value restriction

J

JKop

Here's a little pickle I've been pondering over. I've simplified it down for
posting, here goes:


Consider a function as simple (and as dumb) as the following:


bool IsAfter1998(Year year)
{
return (year > 1998);
}



So let's define the "Year" type. We start off with:


typedef int Year;


I want to restrict the value of a "Year" to not being 0 ( 1 BC is followed
by 1 AD). I've started off with this:


class Year
{
private:

int data;

void Set(int year)
{
if ( year == 0 ) throw bad_year();

data = year;
}

public:

class bad_year {};

explicit Year(int year = 1)
{
Set(year);
}

Year& operator=(Year year)
{
Set(year);

return *this;
}

operator int()
{
return data;
}

};


I figured a lot of people have probably done something like this before. So
can anyone suggest any suitable alternatives or maybe tweek my code a
little?

Particularly with my code, I realize that one can't do the following:

Year year;

++year;


-JKop
 
T

Thomas Matthews

JKop said:
Here's a little pickle I've been pondering over. I've simplified it down for
posting, here goes:


Consider a function as simple (and as dumb) as the following:


bool IsAfter1998(Year year)
{
return (year > 1998);
}



So let's define the "Year" type. We start off with:


typedef int Year;


I want to restrict the value of a "Year" to not being 0 ( 1 BC is followed
by 1 AD). I've started off with this:


class Year
{
private:

int data;

void Set(int year)
{
if ( year == 0 ) throw bad_year();

data = year;
}

public:

class bad_year {};

explicit Year(int year = 1)
{
Set(year);
}

Year& operator=(Year year)
{
Set(year);

return *this;
}

operator int()
{
return data;
}

};


I figured a lot of people have probably done something like this before. So
can anyone suggest any suitable alternatives or maybe tweek my code a
little?

Particularly with my code, I realize that one can't do the following:

Year year;

++year;


-JKop

I love integers:
Year sci_fic;
sci_fic = -20;
sci_fic++;
sci_fic--;
sci_fic /= 40;

By the way, you could use _unsigned_int_ if you
want the compiler to restrict the year to postive
values.

One idea is to have an inline function that validates
a year:
inline Validate_Year(unsigned int year)
{
if (year < 1)
throw Your_Favorite_Exception();
return;
}

I believe this would have minimal impact since it
is declared as inline.

I don't see any need to complicate the code by
creating a separate year class. Nor, IMHO, any
special reason to make the year a separate type.


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

red floyd

Thomas said:
By the way, you could use _unsigned_int_ if you
want the compiler to restrict the year to postive
values.

He doesn't want to restrict to positive, he wants to restrict to
*NON-ZERO*. Slightly different.
 
R

Ron Natalie

JKop said:
Here's a little pickle I've been pondering over. I've simplified it down for
posting, here goes:
Your copy constructor seems a bit spurious. If you can't construct an invalid year
object, how could you ever get an invalid one to copy?

I detest implicit conversion operators.

Yes, you are going to have to define mathematic operators. Think about how pointers/iterators
work. The subtraction of two years is some integral type, but years should not otherwise implicitly
convert to/from numerics.
 
J

JKop

Ron Natalie posted:

Your copy constructor seems a bit spurious. If you can't construct an
invalid year object, how could you ever get an invalid
one to copy?


If by spurious you mean absent, then yes.

What you think of my assignment operator?

I detest implicit conversion operators.

Yes, you are going to have to define mathematic operators. Think
about how pointers/iterators work. The subtraction of two years is
some integral type, but years should not otherwise implicitly convert
to/from numerics.

I disagree: a year *is* a number. Anyway, that was just an
example.

I wonder if it'd be appropriate to increment -1 to 1?

Year& operator++()
{
return ( data == -1 ? data = 1 : data += 1 );
}

Year& operator--()
{
return ( data == 1 ? data = -1 : data -= 1 );
}


-JKop
 
J

JKop

Year& operator++()
{
return ( data == -1 ? data = 1 : data += 1 );
}

Year& operator--()
{
return ( data == 1 ? data = -1 : data -= 1 );
}

Opps!


Year& operator++()
{
data == -1 ? data = 1 : data += 1 ;

return *this;
}

Year& operator--()
{
data == 1 ? data = -1 : data -= 1 ;

return *this;
}


-JKop
 
K

Karl Heinz Buchegger

JKop said:
Ron Natalie posted:

one to copy?

If by spurious you mean absent, then yes.

What you think of my assignment operator?

I think it is not needed.
One of the premises is that it is impossible to create
an invalid Year object. So whetever is passed to the assignment
operator *must* be a valid Year object. Thus the test if it
is valid is not neccessary. A simple assignment of the data
member is sufficient. But this is what the compiler generated
operator does anyway, so it is better to let the compiler take
care of op= instead of writing your own.
I wonder if it'd be appropriate to increment -1 to 1?

Sure, why not.
Year& operator++()
{
return ( data == -1 ? data = 1 : data += 1 );
}

But not like this.
it needs to return *this.
Year& operator--()
{
return ( data == 1 ? data = -1 : data -= 1 );
}

Same. return *this;

With other operators there is a problem on the horizon.

The problem I see is this: What is the return value of op- ?
Is it Year? Well, in every day speaking we say so, but is that really
true. Is a YearSpan the same thing as a Year?
Lets take the conservative approach and say: No. The result of
subtracting 1960 from 1940 is not a Year object, but a YearSpan object.
That makes sense, since adding 1940 with 1980 doesn't really make sense.
But adding 40 years (a YearSpan object) to 1980 makes perfectly sense.

What about op* and op- ?
Does it make sense to calulate 1940 * 1980 ?
I would say no. But it would make sense to allow op/ and op* for
a YearSpan object. 1940 + 2 * 40_years seems reasonable: add 2 times
the amount of 40 years (as YearSpan) to 1940.
 
J

JKop

Have the C++ dudes considered "allowing" the following?:


class Year : public int
{
// Hijack the constructor and all the = operators, += -= *=
/= etc.

}


Ofcourse you wouldn't have any virtual members, but that
wouldn't be a problem:

bool IsAfter1998(Year year)
{
return (year > 1998)
}


I hear in other languages you can inherit from the
intrinsic types... no?

Actually, right now this moment I've thought of an
alternative:

class Int
{
//All sorts of operators

operator int+() //...

};


class Year : public Int ...


Just create an Int class that acts EXACTLY like an int...
(but maybe give it defined overflow behavior ;-) )


-JKop
 
K

Karl Heinz Buchegger

JKop said:
Have the C++ dudes considered "allowing" the following?:

class Year : public int
{
// Hijack the constructor and all the = operators, += -= *=
/= etc.

}

Sorry. That's not allowed :)
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top