TEAM-ADA Archives

Team Ada: Ada Programming Language Advocacy


Options: Use Classic View

Use Monospaced Font
Show HTML Part by Default
Condense Mail Headers

Topic: [<< First] [< Prev] [Next >] [Last >>]

Print Reply
Sender: "Team Ada: Ada Advocacy Issues (83 & 95)" <[log in to unmask]>
Date: Fri, 20 Aug 1999 21:57:06 -0400
Reply-To: Matthew Heaney <[log in to unmask]>
Content-type: text/plain; charset="US-ASCII"
From: Matthew Heaney <[log in to unmask]>
Content-transfer-encoding: 7bit
Mime-version: 1.0
Parts/Attachments: text/plain (97 lines)
> --  procedure Invalid_Data_Loop_Test
> --
> --  author  : rick duley
> --  date    : August 15, 1999
> --  purpose : to demonstrate the need for a 'Skip_Line' in an exception
> --          :   handler to avoid the program going into an endless
> --          :   loop after a 'Get' call when the exception is an Ada
> --          :   pre-defined exception but that it doesn't seem to
> --          :   matter when the exception is user-defined

For interactive input, you always have to do a Skip_Line following Get.  But
no one ever remembers to do this, and ends up in an infinate loop.
Therefore, as others have pointed out, it's simpler to just always use
Get_Line, and parse the input text yourself.

I don't regard this as a flaw, really; more as a feature, one that needs to
be advertised.

The technique of using Get_Line and parsing the input manually (via T'Value,
etc) lends itself to all kinds of interesting possibilities, like using
non-numeric text as a legitimate input value:

    Line : String (1 .. 80);
    Last : Natural;
    Value : Integer;
    <<Get_Input>> null;
    Get_Line (Line, Last);

    if Last = 0 then
      goto Operation_Cancelled;
      --Put_Line ("No input value entered; try again.");
      --goto Get_Input;

    elsif Last = 1 then

      if Line (1) = 'f' or Line (1) = 'F' then
        Value := 0;
        goto Input_Done;

      elsif Line (1) = 'l' or Line (1) = 'L' then
        Value := 100;
        goto Input_Done;

      elsif Line (1) = 'x' or Line (1) = 'X' then
        goto Operation_Cancelled;

        Put_Line ("Bad input; try again.");
        goto Get_Input;

      end if;

    else -- (last > 1) integer text assumed

        Value := Integer'Value (Line (1 .. Last));
        when Constraint_Error =>
          Put_Line ("The input '" & Line (1 .. Last) &
                    "' is bad; try again.");
          goto Get_Input;

      goto Input_Done;

    end if;

    <<Input_Done>> null;

    <<Operation_Cancelled>> null;

You get the idea -- it's just a little finite state machine.  This is my
standard technique for interactive input.  Use Get_Line, and interrogate the
text myself.  I never bother with Get, as there are too many headaches wrt
exception handling.

> Why is it that user-defined exceptions are treated in a different manner
> from the pre-defined ones?

They aren't.  Try instantiating your package using an Integer subtype, say

  subtype My_Int is Integer range 0 .. 100;

and see what happens.

> What happens to the <LT> character (which I assume to be remaining in the
> buffer and causing the loop) in the Range_Error situation?

The line terminator is still there.