# Ada Programming/Error handling

## Error handling techniques

This chapter describes various error handling techniques. First the
technique is described, then its use is shown with an example function
and a call to that function. We use the √ function which should report
an error condition when called with a negative parameter.

To be specific: Exceptions is the Ada way to go.

### Return code

` Error_Handling_1 `\
\
`  `` Square_Root (X : `` Float) `` Float `\
`     `` Ada.Numerics.Elementary_Functions;`\
`  `\
`     `` X < 0.0 `\
`        `` -1.0;`\
`     `\
`        `` Sqrt (X);`\
`     `` ``;`\
`  `` Square_Root;`\
\
\
\
`  C := Square_Root (A ** 2 + B ** 2);`\
\
`  `` C < 0.0 `\
`     T_IO.Put ("C cannot be calculated!");`\
`  `\
`     T_IO.Put ("C is ");`\
`     F_IO.Put`\
`       (Item => C,`\
`        Fore => F_IO.Default_Fore,`\
`        Aft  => F_IO.Default_Aft,`\
`        Exp  => F_IO.Default_Exp);`\
`  `` ``;`\
\
` Error_Handling_1;`

Our example makes use of the fact that all valid return values for √ are
positive and therefore -1 can be used as an error indicator. However
this technique won\'t work when all possible return values are valid and
no return value is available as error indicator; hence to use this
method is a very bad idea.

### Error (success) indicator parameter

An error condition is returned via additional *out* parameter.
Traditionally the indicator is either a boolean with \"true = success\"
or an enumeration with the first element being \"Ok\" and other elements
indicating various error conditions.

` Error_Handling_2 `\
\
` `` Square_Root`\
`    (Y       : `` Float;`\
`     X       : ``  Float;`\
`     Success : `` Boolean)`\
`  `\
`     `` Ada.Numerics.Elementary_Functions;`\
`  `\
`     `` X < 0.0 `\
`        Y       := 0.0;`\
`        Success := False;`\
`     `\
`        Y       := Sqrt (X);`\
`        Success := True;`\
`     `` ``;`\
`     ``;`\
`  `` Square_Root;`\
\
\
\
`  Square_Root`\
`    (Y       => C,`\
`     X       => A ** 2 + B ** 2,`\
`     Success => Success);`\
\
`  `` Success `\
`     T_IO.Put ("C is ");`\
`     F_IO.Put (Item => C);`\
`  `\
`     T_IO.Put ("C cannot be calculated!");`\
`  `` ``;`\
\
` Error_Handling_2;`

One restriction for Ada up to Ada 2005 is that functions cannot have out
parameters. (Functions can have any side effects but may not show them).
So for our example we had to use a procedure instead. The bad news is
that the Success parameter value can easily be ignored.

In Ada 2012, functions may have parameters of any mode; hence this is
possible at last:

` `` Square_Root`\
`    (X       : ``  Float;`\
`     Success : `` Boolean) `` Float`\
`  `\
`    ...`

This technique does not look very nice in mathematical calculations;
hence no good idea either.

### Global variable

An error condition is stored inside a global variable. This variable is
then read directly or indirectly via a function.

` Error_Handling_3 `\
\
`  Float_Error : Boolean;`\
\
`  `` Square_Root (X : `` Float) `` Float`\
`  `\
`     `` Ada.Numerics.Elementary_Functions;`\
`  `\
`     `` X < 0.0 `\
`        Float_Error := True;`\
`        `` 0.0;`\
`     `\
`        `` Sqrt (X);`\
`     `` ``;`\
`  `` Square_Root;`\
\
\
\
`  Float_Error := False;  -- reset the indicator before use`\
`  C := Square_Root (A ** 2 + B ** 2);`\
\
`  `` Float_Error `\
`     T_IO.Put ("C cannot be calculated!");`\
`  `\
`     T_IO.Put ("C is ");`\
`     F_IO.Put`\
`       (Item => C,`\
`        Fore => F_IO.Default_Fore,`\
`        Aft  => F_IO.Default_Aft,`\
`        Exp  => F_IO.Default_Exp);`\
`  `` ``;`\
\
` Error_Handling_3;`

As you can see from the source, the problematic part of this technique
is choosing the place at which the flag is reset. You could either have
the callee or the caller do that.

Also this technique is not suitable for multithreading.

Use of global variables for cases like this indeed is a very bad idea,
in effect one of the worst.

### Exceptions

Ada supports a form of error handling that has long been used by other
languages like the classic `ON ERROR GOTO ...` from early Basic dialects
to the `try ... catch` exception handling from modern object oriented
languages.

The idea is: You register some part of your program as error handler to
be called whenever an error happens. You can even define more than one
handler to handle different kinds of errors separately. Once an error
occurs, the execution jumps to the error handler and continues there; it
is impossible to return to the location where the error occurred.

This is the Ada way!

` Error_Handling_4 `\
\
`  Root_Error: ``;`\
\
`  `` Square_Root (X : `` Float) `` Float `\
`     `` Ada.Numerics.Elementary_Functions;`\
`  `\
`     `` X < 0.0 `\
`        `` Root_Error;`\
`     `\
`        `` Sqrt (X);`\
`     `` ``;`\
`  `` Square_Root;`\
\
\
\
`   C := Square_Root (A ** 2 + B ** 2);`\
\
`   T_IO.Put ("C is ");`\
`   F_IO.Put`\
`       (Item => C,`\
`        Fore => F_IO.Default_Fore,`\
`        Aft  => F_IO.Default_Aft,`\
`        Exp  => F_IO.Default_Exp);`\
\
`   `` Root_Error =>`\
`      T_IO.Put ("C cannot be calculated!");`\
\
` Error_Handling_4;`

The great strength of exceptions handling is that it can block several
operations within one exception handler. This eases the burden of error
handling since not every function or procedure call needs to be checked
independently for successful execution.

### Design by contract

In Design by Contract (DbC), operations must be called with the correct
parameters. This is the caller\'s part of the contract. If the subtypes
of the actual arguments match the subtypes of the formal arguments, and
if the actual arguments have values that make the function\'s
preconditions True, then the subprogram gets a chance to fulfill its
postcondition. Otherwise an error condition occurs.

Now you might wonder how that is going to work. Let\'s look at the
example first:

` Error_Handling_5 `\
\
`  `` Square_Root_Type `` Float `` 0.0 .. Float'``;`\
` `\
`  `` Square_Root`\
`    (X    : `` Square_Root_Type)`\
`     `` Square_Root_Type`\
`  `\
`     `` Ada.Numerics.Elementary_Functions;`\
`  `\
`     `` Sqrt (X);`\
`  `` Square_Root;`\
\
\
\
`  C := Square_Root (A ** 2 + B ** 2);`\
\
`  T_IO.Put ("C is ");`\
`  F_IO.Put`\
`    (Item => C,`\
`     Fore => F_IO.Default_Fore,`\
`     Aft  => F_IO.Default_Aft,`\
`     Exp  => F_IO.Default_Exp);`\
\
`  ``;`\
` Error_Handling_5;`

As you can see, the function requires a precondition of `X >= 0` ---
that is, the function can only be called when
`<var>`{=html}X`</var>`{=html} ≥ 0. In return the function promises as
postcondition that the return value is also ≥ 0.

In a full DbC approach, the postcondition will state a relation that
fully describes the value that results when running the function,
something like `result ≥ 0 and X = result * result`. This postcondition
is √\'s part of the contract. The use of assertions, annotations, or a
language\'s type system for expressing the precondition `X >= 0`
exhibits two important aspects of Design by Contract:

1.  There can be ways for the compiler, or analysis tool, to help check
    the contracts. (Here for example, this is the case when `X ≥ 0`
    follows from X\'s subtype, and √\'s argument when called is of the
    same subtype, hence also ≥ 0.)
2.  The precondition can be mechanically checked **before** the function
    is called.

The 1st aspect adds to safety: No programmer is perfect. Each part of
the contract that needs to be checked by the programmers themselves has
a high probability for mistakes.

The 2nd aspect is important for optimization --- when the contract can
be checked at compile time, no runtime check is needed. You might not
have noticed but if you think about it: $A^2 + B^2$ is never negative,
*provided* the exponentiation operator and the addition operator work in
the usual way.

We have made 5 nice error handling examples for a piece of code which
never fails. And this is the great opportunity for controlling some
runtime aspects of DbC: You can now safely turn checks off, and the code
optimizer can omit the actual range checks.

DbC languages distinguish themselves on how they act in the face of a
contract breach:

1.  True DbC programming languages combine DbC with exception handling
    --- raising an exception when a contract breach is detected at
    runtime, and providing the means to restart the failing routine or
    block in a known good state.
2.  Static analysis tools check all contracts at analysis time and
    demand that the code written in such a way that no contract can ever
    be breached at runtime.

Ada 2012 has introduced pre- and postcondition aspects.

## See also

### Wikibook

-   Ada Programming
-   Ada Programming/Exceptions

### Ada 95 Reference Manual

-   
-   
### Ada 2005 Reference Manual

-   
-   
