comp.lang.ada
 help / color / mirror / Atom feed
* Portable End_Error handling desired
@ 1991-11-16 21:45 cis.ohio-state.edu!zaphod.mps.ohio-state.edu!uwm.edu!ogicse!milton!mfeldm
  0 siblings, 0 replies; 5+ messages in thread
From: cis.ohio-state.edu!zaphod.mps.ohio-state.edu!uwm.edu!ogicse!milton!mfeldm @ 1991-11-16 21:45 UTC (permalink / raw)


Ever in search of the elusive portability will-o'-the-wisp, I ask
your help in testing the behavior of this program. The idea is to 
keep the program alive, whatever the nature of the input. (Yes,
I know the best way to do this is read the input line into a string,
etc., but don't want to do it this way).

The program's behavior is predictable and portable EXCEPT when EOF is
entered from the keyboard (ctrl-D on Unix, ctrl-Z on DOS, etc.).
Tests on 6 different compilers produce at least 3 different behaviors,
including in certain cases an undesired propagation of End_Error
out of the exception loop, back to the runtime. Any ideas, Ada fans?

Mike

PS - the behavior if a float literal, or similar, with digits preceding
a non-integer character, is undesirable but portable. I know this.

-- cut here for program

WITH Text_IO;
PROCEDURE ExceptionLoop IS

  PACKAGE My_Int_IO IS New Text_IO.Integer_IO(Integer);

  MinVal : CONSTANT Integer := -10;
  MaxVal : CONSTANT Integer :=  10;
  SUBTYPE SmallInt  IS Integer RANGE MinVal .. MaxVal;

  InputValue: SmallInt;
  Sum:        Integer;
            
BEGIN -- ExceptionLoop

  Sum := 0;

  FOR Count IN 1..5 LOOP -- counts the five values we need to read

    LOOP      -- inner loop just to control robust input
      BEGIN   -- block for exception handler

        Text_IO.Put(Item => "Enter an integer between ");
        My_Int_IO.Put(Item => SmallInt'First, Width => 0);  
        Text_IO.Put(Item => " and ");
        My_Int_IO.Put(Item => SmallInt'Last, Width => 0);  
        Text_IO.Put(Item => " > ");
        My_Int_IO.Get(Item => InputValue);

        EXIT; -- leave the loop only upon correct input

      EXCEPTION
        WHEN Constraint_Error =>
          Text_IO.Put ("Value entered is out of range. Please try again.");
          Text_IO.New_Line;
        WHEN Text_IO.End_Error =>
          Text_IO.Put ("We are not done yet. Don't enter EOF!");
          Text_IO.New_Line;
          Text_IO.Skip_Line;
        WHEN Text_IO.Data_Error =>
          Text_IO.Put ("Value entered not an integer. Please try again.");
          Text_IO.New_Line;
          Text_IO.Skip_Line;

      END;    -- block for exception handler
    END LOOP;
    -- assert: InputValue is in the range MinN to MaxN   

    Sum := Sum + InputValue; -- add new value into Sum
  END LOOP;

  Text_IO.Put (Item => "The sum is ");
  My_Int_IO. Put (Item => Sum, Width => 1);
  Text_IO.New_Line;

END ExceptionLoop;

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Portable End_Error handling desired
@ 1991-11-20  1:17 Michael Feldman
  0 siblings, 0 replies; 5+ messages in thread
From: Michael Feldman @ 1991-11-20  1:17 UTC (permalink / raw)


In article <EACHUS.91Nov19175843@Dr_No.mitre.org> eachus@Dr_No.mitre.org (Rober
t I. Eachus) writes:
>
>     If you are trying to write "bulletproof" code, you need to have a
>procedure that recursively calls itself in its exception handler.  It
>should also be nested in an outer handler, and keep track of depth of
>nesting so that it can give up gracefully before running off the end
>of the stack (or causing him to reboot the machine).
>
Hmmm. I don't really think recursion is necessary to guard against
strange input from the keyboard; a loop will do. The problem I have
is twofold:

(1) keep reading from the keyboard even if EOF (ctrl-Z or ctrl-D)
is pressed. Since EOF means the file is now "empty", the problem is
to recover Standard_Input after fielding the exception. I do NOT
think there is a portable solution to this, because Text_IO doesn't
allow Standard_Input to be closed and then re-opened, at least not
portably. (Doug Bryan agrees.)

(2) raise and handle an exception if e.g. a float literal is entered
when an integer one was expected. If the integral part of the float
literal happens to be in range, it will be read as valid, raising no
exception, and leaving the decimal point and the fractional part in the 
buffer. 

Here there is a portable solution, for example reading a line into a 
string and then parsing it more-or-less manually. This is not suitable for
the 1st-quarter students to whom I am trying to teach exception handling.

Interactive, human-typed input is the nastiest thing to get right,
whatever the language. It's a fun exercise to see in which ways Ada
makes it marginally easier or harder, but it's messy no matter what.
This is, I think, one reason why some Ada teachers prefer to hide all the
messiness in their own package, keeping the students away from the
details. This is a valid approach, but I prefer not to send the students
off to use packages whose bodies they won't understand before the course
is over. Better to have them learn that the world is messy.

Mike

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Portable End_Error handling desired
@ 1991-11-20  1:58 Robert I. Eachus
  0 siblings, 0 replies; 5+ messages in thread
From: Robert I. Eachus @ 1991-11-20  1:58 UTC (permalink / raw)


     If you are trying to write "bulletproof" code, you need to have a
procedure that recursively calls itself in its exception handler.  It
should also be nested in an outer handler, and keep track of depth of
nesting so that it can give up gracefully before running off the end
of the stack (or causing him to reboot the machine).


					Robert I. Eachus

with STANDARD_DISCLAIMER;
use  STANDARD_DISCLAIMER;
function MESSAGE (TEXT: in CLEVER_IDEAS) return BETTER_IDEAS is...
--

					Robert I. Eachus

with STANDARD_DISCLAIMER;
use  STANDARD_DISCLAIMER;
function MESSAGE (TEXT: in CLEVER_IDEAS) return BETTER_IDEAS is...

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Portable End_Error handling desired
@ 1991-11-22 21:34 Robert I. Eachus
  0 siblings, 0 replies; 5+ messages in thread
From: Robert I. Eachus @ 1991-11-22 21:34 UTC (permalink / raw)


In article <1991Nov20.011726.4124@milton.u.washington.edu> mfeldman@milton.u.wa
shington.edu (Michael Feldman) writes:

   Hmmm. I don't really think recursion is necessary to guard against
   strange input from the keyboard; a loop will do...

   But it is!  There are two cases.  First, I'm sure that you realize
that every I/O read must be done in the scope of an exception handler,
even if the read is in an exception handler.

   Second, and not really described anywhere in Ada books because it
is an operating system thing is that for I/O you should always be in
the scope of multiple handlers.  The problem is that when you get to
the exception handler, you MUST be ready to immediately field another
exception.  On computers without time sharing the situation occurs
only infrequently, but on a time shared machine it is hard to avoid a
situation where the input handler queues signals for two or more
separate exceptions/conditions/interrupts while your process is
inactive.

   Polite OS's will give your process a few microseconds to cope with
the first signal, but don't count on it.  I usually do attempt to deal
with more than two signals back-to-back though.  For example, most
systems will queue a "wake up I've got input" just once, but are quite
willing to follow that immediately by a break (or file closing).  This
sounds like what you are hitting.  (And yes, it would be nice if the
Ada run-time could handle the race condition cleanly, but on some
systems (hardware or operating) it just is not possible, and you have
to be ready to deal with the situation.


					Robert I. Eachus

with STANDARD_DISCLAIMER;
use  STANDARD_DISCLAIMER;
function MESSAGE (TEXT: in CLEVER_IDEAS) return BETTER_IDEAS is...
--

					Robert I. Eachus

with STANDARD_DISCLAIMER;
use  STANDARD_DISCLAIMER;
function MESSAGE (TEXT: in CLEVER_IDEAS) return BETTER_IDEAS is...

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Portable End_Error handling desired
@ 1991-12-12 22:06 Robert I. Eachus
  0 siblings, 0 replies; 5+ messages in thread
From: Robert I. Eachus @ 1991-12-12 22:06 UTC (permalink / raw)


In article <1991Nov20.011726.4124@milton.u.washington.edu> mfeldman@milton.u.wa
shington.edu (Michael Feldman) writes:

   In article <EACHUS.91Nov19175843@Dr_No.mitre.org> eachus@Dr_No.mitre.org (Ro
bert I. Eachus) writes:

   >     If you are trying to write "bulletproof" code, you need to have a
   >procedure that recursively calls itself in its exception handler.  It
   >should also be nested in an outer handler, and keep track of depth of
   >nesting so that it can give up gracefully before running off the end
   >of the stack (or causing him to reboot the machine).

   Hmmm. I don't really think recursion is necessary to guard against
   strange input from the keyboard; a loop will do. The problem I have
   is twofold:

-- Loop or recursion is fine, I just happen to find recusrion
-- "simpler."  My main point was that most systems will allow two
-- exceptions while reading one line of input, so you need at least
-- doubly nested exception handlers in the ordinary case.

   (1) keep reading from the keyboard even if EOF (ctrl-Z or ctrl-D)
   is pressed. Since EOF means the file is now "empty", the problem is
   to recover Standard_Input after fielding the exception. I do NOT
   think there is a portable solution to this, because Text_IO doesn't
   allow Standard_Input to be closed and then re-opened, at least not
   portably. (Doug Bryan agrees.)

-- See AI-48.  Actually, on most implementations it is easier to
-- manipulate CURRENT_INPUT, but I think that was what you meant
-- anyway.   In any case, the "real" name of STANDARD_INPUT is
-- implementation dependant, but who cares:

   STD_IO_NAME: constant String := Text_IO.NAME(Text_IO.STANDARD_INPUT);
   MY_FILE: Text_IO.File_Type;

-- Save ahead of time since some implementations raise USE_ERROR for
-- calls of NAME for a closed file.
   ...
   exception
     when TEXT_IO.STATUS_ERROR =>
       Text_IO.Open(My_File,Text_IO.In_File);
       Text_IO.Set_Input(My_File);
   end;

-- In theory USE_ERROR can be raised by the call to OPEN (or for that
-- matter to NAME), but only in cases where opening STANDARD_IN is not
-- permitted by the system.  However if say control-D hangs up
-- the terminal, I don't know what any Ada compiler could do about it.

   (2) raise and handle an exception if e.g. a float literal is entered
   when an integer one was expected. If the integral part of the float
   literal happens to be in range, it will be read as valid, raising no
   exception, and leaving the decimal point and the fractional part in the 
   buffer.

-- This is a silly oversight...was in 1982, is worse now.  Every
-- implementation has a "peek" operation to look at the next character
-- in TEXT_IO, but it is not exported to users.  I usually build one
-- that uses the support packages used by the vendor to write Text_IO.

   Here there is a portable solution, for example reading a line into a 
   string and then parsing it more-or-less manually. This is not suitable for
   the 1st-quarter students to whom I am trying to teach exception handling.

-- Here I have to disagree.  Whatever esle you might say about line at
-- a time IO, it certainly is the simplest form of IO to get right.

   Interactive, human-typed input is the nastiest thing to get right,
   whatever the language. It's a fun exercise to see in which ways Ada
   makes it marginally easier or harder, but it's messy no matter what.

-- Oh, maybe we do agree.

   This is, I think, one reason why some Ada teachers prefer to hide all the
   messiness in their own package, keeping the students away from the
   details. This is a valid approach, but I prefer not to send the students
   off to use packages whose bodies they won't understand before the course
   is over. Better to have them learn that the world is messy.

-- I really am impressed if your students can understand the body of
-- TEXT_IO after their first Ada course.  How can I hire some?

   :-) :-) :-) (For the humor impaired.)

-- I have done TEXT_IO implementations in Ada, and although I usually
-- pride myself on the high level of software engineering in my
-- products.  However, there are always places in the body of TEXT_IO
-- where I find I need to insert several paragraphs of comments so
-- that I can remember what I did next time I go back to that line.
-- One of these is correctly setting the point where reading stops in
-- an invalid numeric literal.

--

					Robert I. Eachus

with STANDARD_DISCLAIMER;
use  STANDARD_DISCLAIMER;
function MESSAGE (TEXT: in CLEVER_IDEAS) return BETTER_IDEAS is...

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~1991-12-12 22:06 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1991-11-16 21:45 Portable End_Error handling desired cis.ohio-state.edu!zaphod.mps.ohio-state.edu!uwm.edu!ogicse!milton!mfeldm
  -- strict thread matches above, loose matches on Subject: below --
1991-11-20  1:17 Michael Feldman
1991-11-20  1:58 Robert I. Eachus
1991-11-22 21:34 Robert I. Eachus
1991-12-12 22:06 Robert I. Eachus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox