Why is Ada not trapping this specified range check?
The definition of 'Image says:
For every scalar subtype S:
S'Image denotes a function with the following specification:
function S'Image(Arg : S'Base) return String
As you can see, it takes a parameter of the base (unconstrained) type
You have a couple of pretty good answers, but I'm going to add another because it's clear that you expect the expression D + 1.0
to raise an exception, and the answers you have don't explain why it doesn't.
A type declaration like
type T_Norm is new float range -1.0 .. 1.0;
is roughly equivalent to
type T_Norm'Base is new Float;
subtype T_Norm is T_Norm'Base range -1.0 .. 1.0;
The type (called the "base type") isn't given a name, though it can often be referenced with the 'Base
attribute. The name that is given is to a subtype, called the "first-named subtype".
This distinction is important and is often not given enough attention. As explained by egilhh, T_Norm'Image
is defined in terms of T_Norm'Base
. This is also true of the arithmetic operators. For example, "+"
is defined as
function "+" (Left : in T_Norm'Base; Right : in T_Norm'Base) return T_Norm'Base;
2.0 is clearly in the range of T_Norm'Base
, so evaluating D + 1.0
doesn't violate any constraints, nor does passing it to T_Norm'Image
. However, when you try to assign the resulting value to D
, which has subtype T_Norm
, a check is performed that the value is in the range of the subtype, and an exception is raised because the check fails.
This distinction is used in other places to make the language work reasonably. For example, a constrained array type
type A is array (1 .. 10) of C;
is roughly equivalent to
type A'Base is array (Integer range <>) of C;
subtype A is A'Base (1 .. 10);
If you do
V : A;
... V (2 .. 4)
you might expect problems because the slice doesn't have the bounds of A
. But it works because the slice doesn't have subtype A
but rather the anonymous subtype A'Base (2 ..4)
.