Chris Hobbs
Chris Hobbs

Reputation: 445

Use of exceptions in Ada

I'm looking for style guidance. In Python, exceptions are used as "normal" operations:

try:
    z = x/y
except ZeroDivisionError:
    z = 73.0    # set z if y is zero

Rather than checking for y being near zero, we do the division and catch the exception.

This type of approach is illustrated in Ada in "Programming in Ada 2012" by John Barnes:

begin
    Tomorrow := Day'Succ(Today);
exception
    when Constraint_Error =>
        Tomorrow := Day'First;

But then, the book goes on to say "This is a really bad example. Exceptions should be used for rarely occurring cases...".

I am new to Ada, is it good Ada programming style to use exceptions to avoid if statements as we do in Python? Or are exceptions really just used in Ada for nasty things?

Upvotes: 7

Views: 2044

Answers (3)

Jeffrey R. Carter
Jeffrey R. Carter

Reputation: 3358

Exceptions exist to signal exceptional situations, ensuring that they are responded to (unlike status codes, which may be ignored), and separating their processing from unexceptional situations. While errors are exceptional situations, not all exceptional situations are errors. For example, when dealing with user input, invalid input is exceptional but expected from time to time; it is reasonable to use exceptions to handle this. I think it was a mistake for Ada to name all of its predefined exceptions with names ending in _Error.

Sometimes it's necessary to use exceptions even when it would be better to avoid them. For example, if a text file ends will a null line, you want to read that file with Ada.Text_IO, and it's important that you read that null line, you cannot use Ada.Text_IO.End_Of_File. You have to keep reading and handle the resulting End_Error exception.

Where you draw the line between special cases and exceptional situations is a matter of skill, experience, and how much thinking you do before generating code. If you need to cycle through a set of values (such as day names) a lot in a system, a coder will sprinkle if statements or block statements with exception handlers throughout the code, a better coder will create a function to do it for each type involved, and a software engineer will recognize an opportunity for reuse and find or create something like PragmARC.Wrapping, and so simply write

Tomorrow := Wrap_Succ (Today);

without worrying whether Wrap_Succ uses an if or an exception handler.

Upvotes: 1

flyx
flyx

Reputation: 39668

A major difference from Python is that in Ada, exceptions are not data types. The only data you can associate with an instance of an exception is a String:

raise My_Exception with "some string";

So when catching an exception, we can only ever know which kind of exception got thrown, and get some String which may be useful for logging, but not so much for programmatically analyzing what went wrong in more detail.

This also means that we don't have a way to chain exceptions, like it is often done e.g. in Java, where an exception is often wrapped inside another exception to hide details while still being able to see in the stack trace what exactly went wrong.

The reason for this is that the language has been designed for exceptions to be used scarcely. Unlike Python, Ada has been designed to target bare metal, where you may want to disable runtime checks for performance reasons. If you do that, you won't get the Constraint_Error on division by zero and the program will have undefined behavior. So using exceptions influences code portability negatively.

Some compilers provide additional options, like the No_Exception_Propagation restriction in GNAT, which allows exception only if they are caught within the same subroutine.

Still, exceptions are a useful tool for communicating failure without completely obstructing normal program flow in the code (you will know what I mean if you've ever written Go, or C). But generally, the Ada Style Guide advises that

Exceptions should be used as part of an abstraction to indicate error conditions that the abstraction is unable to prevent or correct. Because the abstraction is unable to correct such an error, it must report the error to the user.

This means that, if you do have the possibility to correct a problem without using an exception, you should do that, because it should be part of the normal, non-exceptional, program flow.

Upvotes: 6

Jim Rogers
Jim Rogers

Reputation: 5021

Ada exception handling syntax does not use a try-catch mechanism. Because of that the exception handler is often separated from the code raising the exception by many lines of source code. Ada exceptions are expected to be used for truly exceptional problems. A more acceptable style for Ada is shown below.

  if Today < Day'Last then
     Tomorrow := Day'Succ(Today);
  else
     Tomorrow := Day'First;
  end if;

This code pattern retains the relationship between the two conditions in close proximity in the source code. Neither condition is an erroneous condition or an exceptional condition.

Historically Ada style favors readability over compactness of writing, however the Ada 2012 standard does allow conditional expressions such as

Tomorrow := (if Today < Day'Last then Day'Succ(Today) else Day'First);

It may be a matter of taste whether or not to use a conditional expression.

Upvotes: 4

Related Questions