Compile time range checking/asserts
Jonathan M Davis
jmdavisProg at gmx.com
Tue Sep 14 23:35:45 PDT 2010
On Tuesday 14 September 2010 23:26:57 Jonathan M Davis wrote:
> 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
I suppose that I should add that there are static assertions (e.g. static
assert(/*condition*/);), but they're primarily useful for code generation.
Whatever they check has to be known a compile-time. They can't verify the value
of variables which won't be known until runtime.
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list