ModuleUnloading
Unloading a module happens frequently when developing new code. It is an inherent part of the edit-compile-go cycle unless BlackBox is restarted as a whole for every iteration. During normal operation of a BlackBox application module unloading it is not expected to occur, i.e. the end user will typically never be bothered with any problems caused by module unloading.
In traditional ETH Oberon systems unloading a module is well known to cause various kinds of problems, depending on the way modules are handled by the runtime system. The problem in general is caused by the fact that after a module has been unloaded any procedure variables (including type bound procedures, of course) pointing to the module are not valid any longer. Calling such a procedure results in a trap or in a system crash. There are two main sources of procedure pointers: Views and Actions.
This note tries to shed some light on the way BlackBox deals with such problems. Based on years of experience with the original ETH Oberon system these problems were well known to the ominc people right from the start of the BlackBox development and BlackBox solves them cleanly.
A trap is considered to be the expected outcome of calling a procedure that does no longer exist. A trap allows one to see that something went wrong and also gives an indication what it was, where it happened, etc. This is not considered a problem as long as it does not lead to a system crash. A system crash can result for two reasons: (1) reusing the memory of the unloaded module for something else. This leads to random code being executed when calling an unloaded procedure. (2) from recursive traps, where the trap handler produces another trap that produces another trap etc. A trap handler that opens a window and displays the stack trace unavoidably broadcasts messages to all views (both in ETH Oberon and BlackBox) and thereby can easily produce recursive traps.
In BlackBox (1) cannot happen because the module's code memory is never reused. It is only marked as unusable. Also (2) is cared for in BlackBox for the most important situation, viz. Views. In BlackBox a trapping view is deactivated automatically and shows a greyed representation of itself. This is not only done for traps resulting from unloaded modules but for all traps that are produced from a view because any trap in a view has some potential for producing a recursive trap.
Another important source of procedure pointers are Actions (Services.Action). In this case there is no real danger of producing recursive traps caused by the trap handler broadcasting messages but there is another problem viz. recurrent traps. The observed behavior is close to a system crash if a periodic action opens a large number of trap windows. In BlackBox an action must therefore decide itself if it is to be reactivated after a trap or not. This is expressed by calling Services.DoLater either at the begin or at the end of the action's Do method. An action that calls Services.DoLater at the end will only produce a single trap, not an endless sequence of recurring traps.
For any situation beyond views and actions, BlackBox offers the CLOSE section of a module. This can be used for doing cleanup work upon module unloading.