Why does Ada compiler let range violations pass?
It does give warning, but why does it let it pass if it is an error in any case? Is there a practical scenario in which this is a useful behaviour?
And most importantly: Why is type declaration a runtime entity?
I mean the 3rd line of the code example is something I expect to be evaluated ahead of time.
I thought that only the 5th line will "make it" into the executable. Why not? Is that something useful? Am I missing or misinterpreting something here?
with Ada.Text_IO;
procedure question is
subtype Test is Natural range -1 .. 10;
begin
Ada.Text_IO.Put_Line ("foobar");
end;
Note: Result is identical with "type Test is new Natural range -1..10;"
Note: GNAT 4.6
This comp.lang.ada message suggests that you need at least -gnato -fstack-check
command line options for Gnat to be a compliant Ada compiler.
However that's not the issue here : the compiler does warn about the range error; with Gnat I get:
gnatmake -gnato -fstack-check question
question.adb:3:35: warning: static value out of range of type "Standard.Natural"
question.adb:3:35: warning: "Constraint_Error" will be raised at run time
and the obvious error at run time.
In this case because the range is static the compiler could have caught the error; but as you are guessing, in general the type cannot be fully determined until runtime, as in the following example.
with Ada.Text_IO;
with Ada.Command_Line;
procedure question is
subtype Arguments is Natural range 1 .. Ada.Command_Line.Argument_Count;
begin
for i in Arguments loop
Ada.Text_IO.Put_Line ("Argument " & integer'image(i) &
" is " & Ada.Command_Line.Argument(i));
declare
OneArg : constant String := Ada.Command_Line.Argument(i);
subtype Characters is Natural range OneArg'range;
begin
null; -- process the string here
end;
end loop;
end;
Here neither subtype is known until you run the program.
The declare block shows a related pattern I find very useful, that allows not just variable [sub]types, but allocates variable sized objects on the stack so that they are automatically reclaimed and re-sized on each loop iteration. (You could allocate with "new" and free with "unchecked_deallocation" as in other languages but very often, as here, there is simply no need)