How to implement a moldable exception

The basic steps are the following:

(1) Define a new subclass of Exception Object << #Exception slots: { #messageText . #tag . #signaler . #signalContext . #handlerContext . #outerContext }; tag: 'Exceptions'; package: 'Kernel' that encapsulates all the data you need your dubugger views.

(2) Add view methods to your exception class with a <gtExceptionView> pragma.

(3) Catch exceptions when they occur, and signal instead your new exception.

Let's look an example where we want to catch errors in playing a GtLudoRecordingGame GtLudoGame << #GtLudoRecordingGame slots: { #moves }; tag: 'Model'; package: 'GToolkit-Demo-Ludo' .

The game already makes use of assertions to detect errors in the game play:

#assert:description: gtSenders 
	& GtLudoMove gtMethodsInClass.
  

We define our own exception LudoMoveAssertionFailure Error << #LudoMoveAssertionFailure slots: { #move }; tag: 'Exceptions'; package: 'GToolkit-Demo-Ludo' which encapsulates the problematic move, and we signal it in GtLudoMove>>#assert:description: assert: aBlock description: aStringOrBlock "Demo of moldable exceptions." <debuggerCompleteToSender> aBlock value ifFalse: [ (LudoMoveAssertionFailure forMove: self) signal: aStringOrBlock value ] , which now overrides Object>>#assert:description: assert: aBlock description: aStringOrBlock "Throw an assertion error if aBlock does not evaluates to true." <debuggerCompleteToSender> "we do the == true check to avoid NonBooleanReceiver error for nonBoolean aBlock values" aBlock value == true ifFalse: [ AssertionFailure signal: aStringOrBlock value ] .

We just add a few simple, forwarding debugger views, namely:

LudoMoveAssertionFailure>>#gtGameViewFor: gtGameViewFor: aView <gtView> <gtExceptionView> ^ aView forward title: 'Game'; priority: 10; object: [ move game ]; view: #gtPositionsFor: , and

LudoMoveAssertionFailure>>#gtMovesViewFor: gtMovesViewFor: aView <gtView> <gtExceptionView> ^ aView forward title: 'Moves'; priority: 20; object: [ move game ]; view: #gtMovesFor:

Each of these views forwards to a view we already have for the Ludo game.

Now we can see the moldable exception in action by provoking exceptions.

Here we try to move without rolling the die first:

GtLudoRecordingGameExamples new bEntersAndPlaysWithAahead
	moveTokenNamed: 'B';
	yourself.
  

Here we try to move the wrong player:

GtLudoRecordingGameExamples new bEntersAndPlaysWithAahead
	roll: 6;
	moveTokenNamed: 'B';
	yourself.
  

In both cases we now get a Debugger with our three debugging views. We can switch back to the regular debugger by clicking the GT Debugger button at the top.