In this question, I asked how to define an unlimited upper bound for a range (turns out that the answer was fairly obvious, but not to someone new to Ada). In the answer, it was suggested to create a Specific Subtype for this.
A specific subtype of of the sort referred to in the question would look like this:
Type Speed is Float range 0 .. Float'Last
Additionally, I've noticed that a good portion of the code in this Ada project has specific types - like Feet_Float
and Meters_Float
and the like. Why is this the preferred practice, as opposed to just putting a range constraint on a basic float
member variable in the class/package?
Ada doesn't prefer subtypes - Ada programmers do.
New types and subtypes (they are different, and both have their uses) help catch so many errors at so little cost or time penalty it's a mystery why good type systems fell so far out of fashion.
For example, recognise that the index for any array belongs to a subtype (possibly anonymous, but accessible as myArray'range
as in for i in myArray'range loop ... end loop;
or subtype myIndextype is myArray'range; theIndex : myIndextype;
and you'll see that every buffer overflow vulnerability - or attack - ever written was simply a type error - or could have been, in Ada.
When you get a bug past the compiler, the first time your executable falls over with an Exception : Constraint_Error
pointing spookily close to the mistake, you'll start to get a sense of the value of range-constrained types.
To expand on this a bit, I'll refer to a couple more Q&As.
First note that the compiler you're probably using, Gnat, may not be strictly Ada compliant unless you add a couple of optional flags on the command line (or project file) as described in the first example. Recent versions have turned some of them on by default.
Here's an example of a subtype being declared, used and going out of visible scope, (in a declare
block, where the range of the subtype is unknown until runtime. Unlike many dynamic typed languages, this is both fast and safe, because the relevant storage is usually on the stack, if you're interested in the implementation details.
And an example of how not to use a declare block.
Here's an extreme example of not only declaring subtypes but telling the compiler how to pack them in storage. Common in embedded programming, either where space is tight (I have a complete digital watch in a processor with 1kbyte memory!) or for accessing specific bits in hardware registers. (Note that this example would be cleaner if updated to use Ada-2012 aspects
.)
And this Q&A briefly covers the difference between new types and subtypes, for someone coming from Java. (I'm a little disappointed none of the Java experts managed an answer before it was closed, describing how they would handle the same issues)
The declaration of specific types has the following benefits:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With