Handling a Division by Zero Exception - LucPrestin/Hidden-Modularity GitHub Wiki

Description

Handling exceptions is an essential part of robust programming. At the same time, throwing and catching exceptions is a complex part of the system. To reduce as much complexity as possible, in order to still be able to keep track of the whole, the handling of a division by zero is a good starting point.

Code

^ TDBCursor traceForBlock: [
    [2 / 0] on: ZeroDivide do: [:ex | ex resume: 0]
]

Hypotheses

  • The handling of division by zero is quite strongly confined to the context of numbers. Accordingly, we expect few involved classes. Most notably, the exception itself, the method context likely to be used for tracking, and the numbers themselves.
  • on:do: sets a marker on the stack to know whether an exception has already been handled. This should also be visible in the trace.

Evaluation

image image
Node size based on incoming and outgoing edges Node size additionally under consideration of edge weights

Hypothesis 1: classes involved

Broadly speaking, the hypothesis seems to be correct. There are a few classes involved, the largest of which belong to the exception control flow or are numbers. Unexpected is the UndefinedObject here.

Hypothese 2: Stack Marker

No meaningful statement can be made here based on the Communicator Graph. It has no explicit class that encapsulates the access to the stack. We could get a more detailed impression of this via the Communicator Method Category Graph:

image image
Communicator Graph Communicator Method Category Graph

Among other things, there is a category Context: private-exceptions. If we have a look over in Squeak we will find the method Context>>handleSignal: with the following content:

handleSignal: exception
	"Sent to handler (on:do:) contexts only.
	Execute the handler action block"

	| val |
	<primitive: 199>  "just a marker, fail and execute the following"
	exception privHandlerContext: self contextTag.
	self deactivateHandler. "Prevent re-entering the action block, unless it is explicitely rearmed"
	val := [self fireHandlerActionForSignal: exception] ensure: [self reactivateHandler].
	self return: val  "return from self if not otherwise directed in handle block"

This is where the pieces come together. First, the method comment indicates that it is specifically a method for on:do:, which is what we were looking for. Then the next comment marks a primitive that sets a marker. This could be the marker we are looking for.

Even though we couldn't see the marker directly, the Communicator Method Category Graph still put us on the right track.

Further insights (optionally)