Declare variables with valid range?


#1

It seems like a natural extension of how variables (immutable by default, mutable if specified) are defined to allow the programmer to dictate a specific range of allowed values for an integer. If I know a value is only valid between 0-1000 the sooner I declare that the better it is for catching bugs, off by one errors, and more…

I’m not sure what exact syntax would work, maybe:

let mut(0,1000) x = 0i;

x is only valid from 0-1000 inclusive.

Thoughts?


#2

This would require bounds checking (http://en.wikipedia.org/wiki/Bounds_checking) on every calculation, but that is a not unreasonable tradeoff in many cases.


#3

This RFC suggested range checking, but was not accepted (too complex) :


#4

Doesn’t Rust have enough support for operator overloading to be able to build a reasonable RangedNumber library without needing explicit language support? That seems to have been enough for C++ users over the years. I suppose it might be nice to have range checking for the builtin types available in debug builds, but I’d be very wary of putting a range constraint in code with no guarantee that it’d be enforced in any way.

Twenty years ago when I did some work in Ada for 68020s, it was general practice to put range constraints on everything that moved. I don’t remember anybody ever questioning it, even in a fairly performance-sensitive environment, but I was very wet behind the ears at the time and don’t know how many real bugs this caught in practice.


#5

Not if you want to encode the range in the type, since generic arguments can’t be values. (Well, not without some nasty hack way to encode a number into a type. When constants as associated items are implemented, it won’t be as nasty, though…)


#6

For smallish types, you can use an enum to restrict possible values. But it gets unwieldy as the range gets bigger.


#7

If bounds checking would be performed in runtime, it is not Rust way (zero-cost abstraction). But elsewhere it requires dependent types support and compiler must prove type safety in that case by proving each usage does not try to access value out of bounds. Type checking in such type system may be undecidable, because you cannot even prove equality of two types if they depends of runtime values (function that return list of words it read from stdin, what return type it may have?)


#8

I’m waiting for Rust to get values in generic types, so that it’s possible to implement it as a library.

OTOH if it was built into the language, it could be used in Option optimization (e.g. so that Option<u31> could fit in a 32 bit register).