"What `BadStartingPoint`, `StationaryStartingPoint`, ... are? They are \"types\" of exceptions, or, more generally, \"types\": like `int`, `str`, ...\n",
"What `BadStartingPoint`, `StationaryStartingPoint`, ... are? They are \"types\" of exceptions, or, more generally, \"types\": like `int`, `str`, ...\n",
"\n",
"\n",
"However, they are user-defined types, or `classes`.\n"
"However, they are user-defined types, or `classes`.\n",
" \"\"\"Entry point for launching an IPython kernel.\n"
" \"\"\"Entry point for launching an IPython kernel.\n"
]
]
}
}
...
@@ -650,7 +652,7 @@
...
@@ -650,7 +652,7 @@
"name": "python",
"name": "python",
"nbconvert_exporter": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"pygments_lexer": "ipython3",
"version": "3.6.6"
"version": "3.6.7"
}
}
},
},
"nbformat": 4,
"nbformat": 4,
...
...
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:


%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
# error handling
# error handling
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
Error handling is a complex problem, which the modern languages face off in a completely different way than the "old" ones.
Error handling is a complex problem, which the modern languages face off in a completely different way than the "old" ones.
First, we must be aware of the fact that the place where an error is detected (for example, a library function such as `sqrt`) is not the same place where the error can be "treated" (for example, the main program).
First, we must be aware of the fact that the place where an error is detected (for example, a library function such as `sqrt`) is not the same place where the error can be "treated" (for example, the main program).
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
The requirements of a modern system for handling errors are:
The requirements of a modern system for handling errors are:
* Low or no impact on performance, when no error are generated
* Low or no impact on performance, when no error are generated
* Little invasiveness on code
* Little invasiveness on code
* You should not have to "pass" the error by hand
* You should not have to "pass" the error by hand
* It must be possible to manage the error "partially" (sometimes you can not completely solve the error at one point, but you can apply only a part of the correction)
* It must be possible to manage the error "partially" (sometimes you can not completely solve the error at one point, but you can apply only a part of the correction)
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
Suppose you have a stack of function calls like this:
Suppose you have a stack of function calls like this:
```
```
main
main
|__compute_matrix <- here the error ZeroDivisionError can be handled completely
|__compute_matrix <- here the error ZeroDivisionError can be handled completely
|__compute_cell <- here the errot BadStartingPoint can be handled, and the error
|__compute_cell <- here the errot BadStartingPoint can be handled, and the error
| ZeroDivisionError can be handled partially
| ZeroDivisionError can be handled partially
|__compute_radix_of_function
|__compute_radix_of_function
|__ newton -> here the error BadStartingPoint can be detected
|__ newton -> here the error BadStartingPoint can be detected
|__function_C -> here the error ZeroDivisionError can be detected
|__function_C -> here the error ZeroDivisionError can be detected
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
In Fortran, for example, it is used a variable returned by the function/subroutine to pass any error.
In Fortran, for example, it is used a variable returned by the function/subroutine to pass any error.
In this case, the variable containing the error should be passed manually backwards, for example from `function_C`, to `newton`, to `compute_radix_of_function`, to `compute_cell`, to `compute_matrix`.
In this case, the variable containing the error should be passed manually backwards, for example from `function_C`, to `newton`, to `compute_radix_of_function`, to `compute_cell`, to `compute_matrix`.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
What are the drawbacks?
What are the drawbacks?
* It is a tedious and boring activity that normally lead to errors
* It is a tedious and boring activity that normally lead to errors
* It makes the code much longer and more complicated
* It makes the code much longer and more complicated
* Adds overhead even without error (there will be some __if__ checking the state variables of the function that generates the error, for example).
* Adds overhead even without error (there will be some __if__ checking the state variables of the function that generates the error, for example).
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
All modern systems use a different approach.
All modern systems use a different approach.
Consider the error BadStartingPoint.
Consider the error BadStartingPoint.
At the point where the error can be identified (newton), an exception of type `BadStartingPoint` is launched. For now, do not worry about what `BadStartingPoint` is: it could be anything, an `int`, a `string`, a `list` etc...
At the point where the error can be identified (newton), an exception of type `BadStartingPoint` is launched. For now, do not worry about what `BadStartingPoint` is: it could be anything, an `int`, a `string`, a `list` etc...
In python, exceptions are launched with the `raise` command. In `fun_B` it will appear something like:
In python, exceptions are launched with the `raise` command. In `fun_B` it will appear something like:
```python
```python
if...:
if...:
raiseBadStartingPoint()
raiseBadStartingPoint()
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
When an exception is launched, the program flow is interrupted, and the stack is automatically "rolled back”, back to the function that called the one who launched the exception, and back again if necessary, up to a point where the error can be "treated". The computation resumes from this point.
When an exception is launched, the program flow is interrupted, and the stack is automatically "rolled back”, back to the function that called the one who launched the exception, and back again if necessary, up to a point where the error can be "treated". The computation resumes from this point.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
How do you determine who can treat a certain error?
How do you determine who can treat a certain error?
It's simple: the code block that could handle a `BadStartingPoint` exception is enclosed in a special section; when that exception occurs, it will be executed the associated handling section. The syntax is based on the python `try/except` statement.
It's simple: the code block that could handle a `BadStartingPoint` exception is enclosed in a special section; when that exception occurs, it will be executed the associated handling section. The syntax is based on the python `try/except` statement.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
Therefore, in the function where we determined that the error can be treated (compute_cell) it is inserted a `try/except` block:
Therefore, in the function where we determined that the error can be treated (compute_cell) it is inserted a `try/except` block:
In the intermediate functions nothing changes: they are not involved from the exception.
In the intermediate functions nothing changes: they are not involved from the exception.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
In the case of `ZeroDivisionError`, however, the handling is more complex: `compute_cell` can partially repair the error, but not completely.
In the case of `ZeroDivisionError`, however, the handling is more complex: `compute_cell` can partially repair the error, but not completely.
The rest of the work is done by `compute_matrix`.
The rest of the work is done by `compute_matrix`.
In this case, the exception is collected, partially managed and relaunched, with the `raise` command:
In this case, the exception is collected, partially managed and relaunched, with the `raise` command:
<pre>
<pre>
# ...
# ...
except ZeroDivisionError as e:
except ZeroDivisionError as e:
print("ERR: ZeroDivisionError: resetting cell")
print("ERR: ZeroDivisionError: resetting cell")
matrix[i][j] = 0.0
matrix[i][j] = 0.0
raise
raise
# ...
# ...
</pre>
</pre>
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
At this point the stack is again rolled back to `compute_matrix`, which completes the error handling.
At this point the stack is again rolled back to `compute_matrix`, which completes the error handling.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
Generally, exceptions are defined hierarchically. In our example, there are three types of BadStartingPoint errors:
Generally, exceptions are defined hierarchically. In our example, there are three types of BadStartingPoint errors:
*`StationaryStartingPoint`
*`StationaryStartingPoint`
*`CyclingStartingPoint`
*`CyclingStartingPoint`
*`SlowlyConvergingStartingPoint`
*`SlowlyConvergingStartingPoint`
`newton` launches all these three errors.
`newton` launches all these three errors.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
These three types of error are handled the same way by compute_cell, but it is possible that other functions that call `newton` must treat them differently.
These three types of error are handled the same way by compute_cell, but it is possible that other functions that call `newton` must treat them differently.
This is accomplished by creating a class `BadStartingPoint`, and the three classes `StationaryStartingPoint`, `CyclingStartingPoint`, `SlowlyConvergingStartingPoint` that inherit from `BadStartingPoint`.
This is accomplished by creating a class `BadStartingPoint`, and the three classes `StationaryStartingPoint`, `CyclingStartingPoint`, `SlowlyConvergingStartingPoint` that inherit from `BadStartingPoint`.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## error handling
## error handling
What `BadStartingPoint`, `StationaryStartingPoint`, ... are? They are "types" of exceptions, or, more generally, "types": like `int`, `str`, ...
What `BadStartingPoint`, `StationaryStartingPoint`, ... are? They are "types" of exceptions, or, more generally, "types": like `int`, `str`, ...
However, they are user-defined types, or `classes`.
However, they are user-defined types, or `classes`.