[comp.lang.ada] Ada exceptions

u-dmfloy%sunset.utah.edu@utah-cs.UUCP (Daniel M Floyd) (09/07/88)

This *must* be the right newsgroup.

In discussing the woes of other languages, I posted an
article about excpetion handling. I thought (and still think)
that some way should be available to specify what action
to take when an exception occurs.

For example:

I'd like to say to the compiler

/* exceptions  sqrt(x) */
/*	if -x then do_this_process */
/*	if overflow then scale_routine_error */
/*	if underflow then return 0 */
/* exceptions + */
/*	if overflow ...

I don't care what syntax is used. There are times when a halt
on a fatal error can be ... fatal. I can't tolerate it at times, so
I end up doing alot of firewalling before calling procedures, and
if I do alot of math, it can get ugly fast.

I've had two messages that say "go Ada".

Can Ada really do it? If it can, I'll likely become a devotee, investing
within the month.

Could some Ada-ite post an Ada example like the one above, in Ada.

Thanks.

eachus@mitre-bedford.ARPA (Robert Eachus) (09/08/88)

In article <5701@utah-cs.UUCP> u-dmfloy%sunset.utah.edu.UUCP@utah-cs.UUCP (Daniel M Floyd) writes:
>This *must* be the right newsgroup.

>In discussing the woes of other languages, I posted an
>article about excpetion handling. I thought (and still think)
>that some way should be available to specify what action
>to take when an exception occurs.

>For example:

>I'd like to say to the compiler

>/* exceptions  sqrt(x) */
>/*	if -x then do_this_process */
>/*	if overflow then scale_routine_error */
>/*	if underflow then return 0 */
>/* exceptions + */
>/*	if overflow ...

>I don't care what syntax is used. There are times when a halt
>on a fatal error can be ... fatal. I can't tolerate it at times, so
>I end up doing alot of firewalling before calling procedures, and
>if I do alot of math, it can get ugly fast.

      What  you want can be  done  easily in Ada,   but  it is not the
normal  Ada style.  It is however  very useful as  a means of handling
certain  functions.  For example,  if I  write  a program which  opens
several files, I usually overload the OPEN  call to provide reasonable
handling of the "normal" error conditions.

     The more normal case is to have a handler cover  a region of code
(for  example all  the  statements  of a procedure)   and do something
sensible if an exception occurs in  that  region.  Belt and suspenders
types  (and  that  includes most  Ada   software engineers) also   put
catastropic error handlers on the entire program.

>I've had two messages that say "go Ada".

>Can Ada really do it? If it can, I'll likely become a devotee, investing
>within the month.

     Yes, but you still have to do the hard part... (Ada syntax and
semantics are a big help, but you have to figure out what to do with
the error. :-)

>Could some Ada-ite post an Ada example like the one above, in Ada.

    First you need a square root routine.  Most compilers come with
math packages, but they are not strictly part of the language, and you
can roll your own.  Assume that the package you use says something
like this:


with MATH_EXCEPTIONS;
generic
   type REAL is digits <>; -- some floating point type
package MATHEMATICAL_FUNCTIONS is
   subtype NON_NEGATIVE is REAL range 0.0..REAL'LAST;
   ...
   function SQRT(L: in NON_NEGATIVE) return  NON_NEGATIVE; 
   -- Returns the positive square root of L.  Result is accurate to
   -- within +/- 2.0*REAL'EPSILON times the correct result. Result is
   -- guarenteed to be greater than L for small positive L. SQRT(0.0)
   -- is always exactly 0.0. If 1.0 is a model number of type REAL,
   -- then SQRT(REAL(N*N)) = REAL(N) for any integer N if N*N is a
   -- model number of type REAL.
   ...
end MATHEMATICAL_FUNCTIONS;

-- Now for your program:

with MATHEMATICAL_FUNCTIONS;
with MATH_EXCEPTIONS; use MATH_EXCEPTIONS;
procedure MAIN is
    X, Y, Z: FLOAT;
    package MATH is new MATHMATICAL_FUNCTIONS(FLOAT);
    procedure DO_THIS_PROCESS;
    ...
    function SQRT(X: in FLOAT) is
      begin
        if X < 0.0 then Do_This_Process; else return MATH.SQRT(X); end if;
        -- Your other cases don't arise...
      end SQRT;
    function "+" (L,R: FLOAT) is -- hides STANDARD."+"
      begin
        return STANDARD'"+"(L,R);
      exception
        when others => ...
      end "+";
    ...
    begin
       ...
       Y := sqrt(X); -- Strong typing assures that no other error can
                     -- occur. Even nicer than handling errors is to
                     -- be able to guarentee that they can't happen.
       Z := X + Y;   -- Your "+" which presumably doesn't overflow.
    end MAIN;

    You may think that  the specification of  SQRT is overkill, but it
is "normal" Ada practice to  specify  which exceptions can be  raised,
and under what conditions, by any function in a library package.

					Robert I. Eachus

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

carllp@freja.dk (Carl-Lykke Pedersen) (09/09/88)

u-dmfloy%sunset.utah.edu@utah-cs.UUCP (Daniel M Floyd) writes:
>I've had two messages that say "go Ada".

"Go (PL/1), MESA, CLU, ML"

PL/1:
     FACTORIAL: PROCEDURE;
	DECLARE (N, F) FIXED FIN (31) INIT (1);
	ON FINISH BEGIN;
	  PUT LIST (N, "FACTORIAL =", F);
	  PUT SKIP;
	  N = N + 1;
	  F = N * F;
	  STOP;
	  END;
	STOP;
     END FACTORIAL;

Ada:
     function DIVIDE_CHECK(X, Y: REAL) return REAL is
	begin
	  if X = 0 then
		raise SILLY;
	  else X/Y;
	  endif;
	exception
	  when NUMERIC_ERROR => return 0;
	  when SILLY => return -1;
     end;

Sorry if the syntax isn't correct. I do not have an Ada-compiler (or a PL/1-
compiler).

Regards
CLp
.

eachus@mitre-bedford.ARPA (Robert Eachus) (09/12/88)

In article <4055@freja.dk> carllp@freja.dk (Carl-Lykke Pedersen) writes:

>PL/1:
>     FACTORIAL: PROCEDURE;
>	DECLARE (N, F) FIXED FIN (31) INIT (1);
>	ON FINISH BEGIN;
>	  PUT LIST (N, "FACTORIAL =", F);
>	  PUT SKIP;
>	  N = N + 1;
>	  F = N * F;
>	  STOP;
>	  END;
>	STOP;
>     END FACTORIAL;

     I'm not sure what the PL/I example is trying to demonstrate, so I
won't try to rewrite it in PL/I, but it is very simple in Ada:

with TEXT_IO;
procedure FACTORIALS is
  type My_Int is range -2**31..2**31-1;
-- Since the program's behavior depends on 32 bit integers,
-- force a type and subtype with the range expected.
  N, F: My_Int := 1;
begin
  loop
    TEXT_IO.Put_Line(My_Int'IMAGE(N) & "FACTORIAL =" & My_Int'IMAGE(F));
    N := N + 1;
    F := F * N;
  end loop;
exception
  when others => TEXT_IO.Put_line("  That's all folks!");
end FACTORIALS;

>Ada:
>     function DIVIDE_CHECK(X, Y: REAL) return REAL is
>	begin
>	  if X = 0 then
>		raise SILLY;
>	  else X/Y;
>	  endif;
>	exception
>	  when NUMERIC_ERROR => return 0;
>	  when SILLY => return -1;
>     end;

>Sorry if the syntax isn't correct. I do not have an Ada-compiler (or a PL/1-
>compiler).

     There  is a missing  "return"   before  X/Y.   If  REAL is not an
integer type, the constants need to contain  decimal points.  There is
a syntactic problem  is much  more  subtle.  A  compiler is allowed to
generate code which computes  X/Y in a  type with wider range and then
convert the result to REAL. (This is  not  just a theoretical case, it
happens  all the  time with IEEE  floating  point.)   This  results in
CONSTRAINT_ERROR being raised   in some cases,   and NUMERIC_ERROR  in
others. There may also  be a programming mistake.   I assume that  you
want to raise SILLY  when  Y is zero,  but I'm not sure, since raising
SILLY when X is zero is certainly silly. :-)

     There  are also  two   problems of  style.   You surely  want the
function named  "/",  unless it  is generic,   and it is bad   form to
declare an exception like SILLY (you did intend to  declare it, didn't
you?) just to handle it locally. So:

  generic
    type REAL is digits <>;
    DIVIDE_BY_ZERO_RETURN_VALUE: in REAL := -1.0;
    OVERFLOW_RETURN_VALUE: in REAL := 0.0;
  function DIVIDE_WITH_ERROR_HANDLING (X, Y: REAL) return REAL is
  begin
    if Y = 0.0
    then return DIVIDE_BY_ZERO_RETURN_VALUE;
    else return X/Y;
    endif;
  exception
    when CONSTRAINT_ERROR | NUMERIC_ERROR => 
      return OVERFLOW_RETURN_VALUE;
  end DIVIDE_WITH_ERROR_HANDLING;

  -- Now it can be instantiated as follows.  I've changed the overflow
  -- default to show how it's done.

  function "/" is new Divide_with_Error_Handling
                 (Float, Overflow_return_value => Float'LAST);


					Robert I. Eachus

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