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