Velocity Reviews > C++ > Value restriction

# Value restriction

JKop
Guest
Posts: n/a

 07-13-2004

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 > 199;
}

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:

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

Thomas Matthews
Guest
Posts: n/a

 07-13-2004
JKop wrote:
> 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 > 199;
> }
>
>
>
> 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:
>
>
> 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

red floyd
Guest
Posts: n/a

 07-13-2004
Thomas Matthews wrote:

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

Ron Natalie
Guest
Posts: n/a

 07-13-2004

"JKop" <(E-Mail Removed)> wrote in message news:tVXIc.4517\$(E-Mail Removed)...
>
> Here's a little pickle I've been pondering over. I've simplified it down for
> posting, here goes:
> > typedef int Year;

>
>

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.

JKop
Guest
Posts: n/a

 07-14-2004
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

JKop
Guest
Posts: n/a

 07-14-2004

> 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

Karl Heinz Buchegger
Guest
Posts: n/a

 07-14-2004
JKop wrote:
>
> 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 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

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

--
Karl Heinz Buchegger
http://www.velocityreviews.com/forums/(E-Mail Removed)

JKop
Guest
Posts: n/a

 07-14-2004
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 > 199
}

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

JKop
Guest
Posts: n/a

 07-14-2004
> operator int+() //...

TYPO

operator int()

-JKop

Karl Heinz Buchegger
Guest
Posts: n/a

 07-14-2004
JKop wrote:
>
> 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

--
Karl Heinz Buchegger
(E-Mail Removed)