Compile time range checking/asserts
Jonathan M Davis
jmdavisProg at gmx.com
Tue Sep 14 23:26:57 PDT 2010
On Tuesday 14 September 2010 22:42:07 Borden Rhodes wrote:
> Good morning, list,
>
> I know that D has support for ranges in for-each statements and in array
> bounds checking, but I'm curious if it also has a facility for compile-time
> range checking or assertions on individual variables.
>
> For example, using the Java Tutorial's venerable Bicycle class, say I
> had a property <code>int gear;</code> which indicated the bicycle's current
> gear. Let's say all bicycles of this class have 6 gears. Typically, I
> would write a changeGear method as:
>
> <code>
> void changeGear(int newGear) {
> if ( 1 <= newGear && newGear <= 6)
> gear = newGear;
> else
> throw SomeKindOfException();
> }
> </code>
>
> which would include the if statement to make sure that newGear would be
> passed a number in the correct range and a throw statement to deal with
> cheaters.
>
> Does D allow - or would there be logic in creating - an ability to define
> the acceptable ranges when the variable is initialised? So, say I wanted
> gear only to accept values between 1 and 6 inclusive. Could I declare
> something to the effect of:
>
> <code>int gear {1...6} = 1;</code>
>
> Which could read, "create a new int, called gear, which only accepts values
> between 1 and 6, inclusive, and initialise it to 1." Then, if I, or some
> coder who forgot how many gears my Bicycle has, tried to call:
>
> </code>bicycle.changeGear( 12 );</code>
>
> the compiler would catch that <code>gear = newGear;</code> is assigning a
> value out of range and throw a compile-time error. Can D do this? Should
> it do this?
>
> With thanks,
>
> Borden
You cannot restrict a primitive type to a specific range of values. You can,
however, use contracts to ensure at runtime that a value is within a specific
range. e.g.
class Bicycle
{
void changeGear(int gear)
in
{
assert(gear >= 1 && gear <= 6);
}
body
{
//do whatever changeGear() does
}
}
So, if you compile in debug mode (i.e. without -release), then the assertion in
the in block will run before the function body does. If it fails, an AssertError
will be thrown. You have it check at compile time though.
Any code which is run at compile-time (e.g. when an enum is instantiated) will
have its contracts run when at compile-time when the code is run, but that's
only for code which is run at compile-time using CTFE (Compile-Time Function
Evaluation).
You could use an enum like so
enum Gear : int {one = 1, two, three, four, five, six};
and the values will be fixed. But Even if you use Gear as the parameter
changeGear(), it won't do any checking beyond the range of the enum type (int in
this case). So, while D has fantastic code generation capabilities, it doesn't
really have much in the way of doing compile-time checks of values outside of
CTFE or template constraints.
So, typicall what you would do is use contracts (in for pre-conditions, out for
post-conditions, and invariant for class/struct invariants) which would run when
the program is run in debug mode.
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list