I've just started learning Ada and I cannot figure out how to keep the program running when the user input is beyond the declared range of a variable. I'd like to print info about bad range of input and then ask user for input again.
This is my simple code:
with Ada.Text_IO; use Ada.Text_IO; procedure Main is type Score is range 0..100; a : Score; begin Put_Line ("Enter value range 0-100: "); a := Score'Value(Get_Line); if a'Valid then Put_Line ("You entered" & Score'Image (a)); else Put_Line ("Bad range of input"); end if; end Main;
Shouldn't I use the "range" in order to check the input, but rather some if's with >, < restrictions?
My other approach was to try this with exceptions, but it also doesn't work as I want it to:
with Ada.Text_IO; with Ada.IO_Exceptions; use Ada.Text_IO; procedure Main is type Score is range 0..100; a : Score; begin loop begin Put_Line ("Enter value range 0-100: "); a := Score'Value(Get_Line); Put_Line ("You entered" & Score'Image (a)); exit; exception when Ada.IO_Exceptions.Data_Error => Put_Line("Bad range of input"); end; end loop; end Main;
I believe the problem is in my lack of understanding this language, but I hope there is some kind of easy solution for this, thanks for any help.
Now you know a magical incantation that works, but I doubt you understand why it works, or why your other incantations didn't work. I will go into painful pedagogical detail about that, in hopes that some of it might be useful or of interest.
In Ada, when you declare a type, the type is anonymous, and the name (
Score) you give is the name of the first-named subtype. The first-named subtype may have constraints that don't apply to the anonymous base type. For some types, including integer types, it's possible to refer to the anonymous base type with
Since you declared
range, it is a signed integer type and its base type is (roughly) symmetrical around zero. So your declaration is equivalent to something like
type Score'Base is range -128 .. 127; subtype Score is Score'Base range 0 .. 100;
(this is not Ada and will not compile).
Score'Value returns a value of
Score'Base (ARM 3.5 (53)), so if you input
Score'Value will succeed and return the appropriate value. When you assign that value to your variable of subtype
Score, a check is performed that the value is in the range of
Score; when that fails,
Constraint_Error is raised. If you input an invalid image, such as
Score'Value fails and raises
Constraint_Error. So you have two kinds of incorrect input resulting in two different failures, both of which happen to raise the same exception.
Your first version failed because you never got to the
if statement. Your second version failed because
Ada.Text_IO.Get_Line never raises
When dealing with numeric input, I advise that a complete line be read into a String and you then parse out the value(s) from that String, as you have done. However,
'Value will reject some input that you might want to consider valid. For example, you might want to accept
"23 skidoo" and get the value 23 from it. For that, you might want to instantiate
Ada.Text_IO.Integer_IO for your numeric (sub)type and use the
Get function that takes a
package Score_IO is new Ada.Text_IO.Integer_IO (Num => Score); ... Score_IO.Get (From => "23 skidoo", Item => A, Last => Last);
A to 23 and
Last to the index of