www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - HowTo: Subtype for restricted range of number type?

reply "Lynn Allan" <l_d_allan adelphia.net> writes:
<alert comment="newbie"?

Is there a way to define a numeric type to have a restricted range?
Ada (and Pascal?) had something like:

subtype Temperatures is short range -50 .. 200;
subtype BookNum is ubyte range 1 .. 66;

Is this done in 'D' by defining an object derived from short or ubyte?
Would this be inefficient? How about the properties .max and .min?

The kind of thing I want to do is have a lookup table such that the
index into the lookup table has to have a restricted one-based range
(from 1 to 66). I can accomplish roughly the equivalent of this with
"dbc in";

ushort GetMaxChap(ushort bk) {
in { assert((bk >= 1) && (bk <= 66));
body {
 ...
}

But can I define a subrange for a type such as
ubyte BookNum bk;
that has to be between 1 and 66? I'd also like to be able for use
"foreach" on all the allowable values of BookNum.

void main() {
  foreach(BookNum) {
  ... some code
  }
  ushort maxChap = GetMaxChap(0); // rejected by compiler
}

ushort GetMaxChap(BookNum bk) {
... return lookup
}

If this syntax isn't available in 'D', what is the appropriate way to
accomplish this for readability and/or efficiency and/or error
minimization?

</alert>
Oct 11 2004
parent "Ben Hinkle" <bhinkle mathworks.com> writes:
"Lynn Allan" <l_d_allan adelphia.net> wrote in message
news:cke3d1$1ehf$1 digitaldaemon.com...
 <alert comment="newbie"?

 Is there a way to define a numeric type to have a restricted range?

not builtin to the language
 Ada (and Pascal?) had something like:

 subtype Temperatures is short range -50 .. 200;
 subtype BookNum is ubyte range 1 .. 66;

 Is this done in 'D' by defining an object derived from short or ubyte?
 Would this be inefficient? How about the properties .max and .min?

Technically speaking since short and ubyte aren't classes one can't derive from them. I'd recommend using either short or ubyte (or aliases for these) and checking the range explicitly as your code below illustrates.
 The kind of thing I want to do is have a lookup table such that the
 index into the lookup table has to have a restricted one-based range
 (from 1 to 66). I can accomplish roughly the equivalent of this with
 "dbc in";

 ushort GetMaxChap(ushort bk) {
 in { assert((bk >= 1) && (bk <= 66));
 body {
  ...
 }

 But can I define a subrange for a type such as
 ubyte BookNum bk;
 that has to be between 1 and 66? I'd also like to be able for use
 "foreach" on all the allowable values of BookNum.

 void main() {
   foreach(BookNum) {
   ... some code
   }
   ushort maxChap = GetMaxChap(0); // rejected by compiler
 }

 ushort GetMaxChap(BookNum bk) {
 ... return lookup
 }

 If this syntax isn't available in 'D', what is the appropriate way to
 accomplish this for readability and/or efficiency and/or error
 minimization?

 </alert>

You could also define variables like "books" that stores an array of Books which contain arrays of Chapters and then the array indexing bounds checking will take care of making sure the values stay inside the ranges (though I suppose the builtin range support could improve compile-time vs run-time checks). So for example instead of foreach(BookNum) { ... some code } looping over a type (which isn't supported by the way) write foreach(Book book; books) { } to loop over the collection of books. And then instead of GetMaxChap(ushort bk) you could get the length property of the chapters field of a given Book. I'm just making up data structures for you on the fly so who knows if arrays of Books containing arrays of Chapters are useful for your app. good luck, -Ben
Oct 11 2004