Error trapping in Dyalog APL forms: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
m (Text replacement - "</source>" to "</syntaxhighlight>")
Line 18: Line 18:


:EndClass
:EndClass
</source>
</syntaxhighlight>


Usage is trivial: <source lang=apl inline>(⎕NEW MyApp).Wait</source>. The <source lang=apl inline>Wait</source> method is enough to keep the <source lang=apl inline>MyApp</source> instance in existence until the <source lang=apl inline>Kill</source> button is clicked. Then everything disappears: no objects left, no clean-up to do.
Usage is trivial: <source lang=apl inline>(⎕NEW MyApp).Wait</syntaxhighlight>. The <source lang=apl inline>Wait</syntaxhighlight> method is enough to keep the <source lang=apl inline>MyApp</syntaxhighlight> instance in existence until the <source lang=apl inline>Kill</syntaxhighlight> button is clicked. Then everything disappears: no objects left, no clean-up to do.


This is an appealing way to code a GUI because of the high degree of encapsulation. Everything the application's GUI needs is contained in the Form. It doesn't even require a name assigned to it.
This is an appealing way to code a GUI because of the high degree of encapsulation. Everything the application's GUI needs is contained in the Form. It doesn't even require a name assigned to it.
Line 26: Line 26:
However, trapping such an application requires a little thought. If your error traps have relied on knowing the names of forms and so on, you will find them difficult to use here.
However, trapping such an application requires a little thought. If your error traps have relied on knowing the names of forms and so on, you will find them difficult to use here.


Let's make the reasonable assumption an error might occur elsewhere in the active workspace, not necessarily in a method of <source lang=apl inline>MyApp</source>. Let's suppose that in the event of an error or an interrupt we want to (a) log the event and local environment, and (b) cut back and either restart or resume the application.
Let's make the reasonable assumption an error might occur elsewhere in the active workspace, not necessarily in a method of <source lang=apl inline>MyApp</syntaxhighlight>. Let's suppose that in the event of an error or an interrupt we want to (a) log the event and local environment, and (b) cut back and either restart or resume the application.


One thing we can't do is cut back the stack so far that <source lang=apl inline>MyApp</source>'s methods are no longer on it. For example, let's insert a domain error into <source lang=apl inline>ButtonHandler</source>:
One thing we can't do is cut back the stack so far that <source lang=apl inline>MyApp</syntaxhighlight>'s methods are no longer on it. For example, let's insert a domain error into <source lang=apl inline>ButtonHandler</syntaxhighlight>:


<source lang=apl>
<source lang=apl>
Line 35: Line 35:
       ÷0
       ÷0
     ∇
     ∇
</source>
</syntaxhighlight>


start it, and push the button.
start it, and push the button.
Line 49: Line 49:
       ⎕THIS
       ⎕THIS
#.[MyApp]
#.[MyApp]
</source>
</syntaxhighlight>


You might think that you could set <source lang=apl inline>⎕TRAP</source> to cut back to the instance and resume, by writing:
You might think that you could set <source lang=apl inline>⎕TRAP</syntaxhighlight> to cut back to the instance and resume, by writing:


<source lang=apl>
<source lang=apl>
       ⎕TRAP←⊂0 'C' '⎕←''TRAPPED'' ⋄ ⎕←↑⎕DM ⋄ Wait'
       ⎕TRAP←⊂0 'C' '⎕←''TRAPPED'' ⋄ ⎕←↑⎕DM ⋄ Wait'
</source>
</syntaxhighlight>


either in the class script or in its constructor. But it turns out that <source lang=apl inline>⎕TRAP</source> is set in the workspace root, not in the object. When the trap fires, the stack is cut back to immediate execution, and the <source lang=apl inline>MyApp</source> instance vanishes.
either in the class script or in its constructor. But it turns out that <source lang=apl inline>⎕TRAP</syntaxhighlight> is set in the workspace root, not in the object. When the trap fires, the stack is cut back to immediate execution, and the <source lang=apl inline>MyApp</syntaxhighlight> instance vanishes.


A more robust approach overrides the <source lang=apl inline>Wait</source> method <source lang=apl inline>MyApp</source> inherited from the <source lang=apl inline>Form</source> class. We can localise <source lang=apl inline>⎕TRAP</source> in <source lang=apl inline>Wait</source>, log the error from the environment in which it occurred, then ensure the stack is cut back only to a point at which we can resume.
A more robust approach overrides the <source lang=apl inline>Wait</syntaxhighlight> method <source lang=apl inline>MyApp</syntaxhighlight> inherited from the <source lang=apl inline>Form</syntaxhighlight> class. We can localise <source lang=apl inline>⎕TRAP</syntaxhighlight> in <source lang=apl inline>Wait</syntaxhighlight>, log the error from the environment in which it occurred, then ensure the stack is cut back only to a point at which we can resume.


<source lang=apl>
<source lang=apl>
Line 73: Line 73:
       :Until done
       :Until done
     ∇
     ∇
</source>
</syntaxhighlight>


Here is a slightly more elaborate version taken from a commercial application. This application's user-interface object needs its error trapping to report what is in its <source lang=apl inline>ThisObj</source> slot.
Here is a slightly more elaborate version taken from a commercial application. This application's user-interface object needs its error trapping to report what is in its <source lang=apl inline>ThisObj</syntaxhighlight> slot.


<source lang=apl>
<source lang=apl>
Line 92: Line 92:
       :Until done
       :Until done
     ∇
     ∇
</source>
</syntaxhighlight>


== See also ==
== See also ==

Revision as of 21:10, 10 September 2022

An application's GUI looks like a Form with stuff on it. So it is appealing to describe it that way. That is to say, to define the GUI as a class derived from a Dyalog native Form.

<source lang=apl>

Class MyApp: 'Form'
   ∇ make
     :Access Public
     :Implements Constructor
     Caption←'My Application'
     BTN←⎕NEW'Button'(⊂'Caption' 'Push me')
     BTN.onSelect←'ButtonHandler'
   ∇
   ∇ ButtonHandler(obj xxx)
     obj.Caption←'Ouch'
   ∇
EndClass

</syntaxhighlight>

Usage is trivial: <source lang=apl inline>(⎕NEW MyApp).Wait</syntaxhighlight>. The <source lang=apl inline>Wait</syntaxhighlight> method is enough to keep the <source lang=apl inline>MyApp</syntaxhighlight> instance in existence until the <source lang=apl inline>Kill</syntaxhighlight> button is clicked. Then everything disappears: no objects left, no clean-up to do.

This is an appealing way to code a GUI because of the high degree of encapsulation. Everything the application's GUI needs is contained in the Form. It doesn't even require a name assigned to it.

However, trapping such an application requires a little thought. If your error traps have relied on knowing the names of forms and so on, you will find them difficult to use here.

Let's make the reasonable assumption an error might occur elsewhere in the active workspace, not necessarily in a method of <source lang=apl inline>MyApp</syntaxhighlight>. Let's suppose that in the event of an error or an interrupt we want to (a) log the event and local environment, and (b) cut back and either restart or resume the application.

One thing we can't do is cut back the stack so far that <source lang=apl inline>MyApp</syntaxhighlight>'s methods are no longer on it. For example, let's insert a domain error into <source lang=apl inline>ButtonHandler</syntaxhighlight>:

<source lang=apl>

   ∇ ButtonHandler(obj xxx)
     obj.Caption←'Ouch'
     ÷0
   ∇

</syntaxhighlight>

start it, and push the button.

<source lang=apl>

     (⎕NEW MyApp).Wait

DOMAIN ERROR ButtonHandler[2] ÷0

               ∧
     )SI

[#.[MyApp]] #.MyApp.ButtonHandler[2]* ⎕DQ

     ⎕THIS
  1. .[MyApp]

</syntaxhighlight>

You might think that you could set <source lang=apl inline>⎕TRAP</syntaxhighlight> to cut back to the instance and resume, by writing:

<source lang=apl>

     ⎕TRAP←⊂0 'C' '⎕←TRAPPED ⋄ ⎕←↑⎕DM ⋄ Wait'

</syntaxhighlight>

either in the class script or in its constructor. But it turns out that <source lang=apl inline>⎕TRAP</syntaxhighlight> is set in the workspace root, not in the object. When the trap fires, the stack is cut back to immediate execution, and the <source lang=apl inline>MyApp</syntaxhighlight> instance vanishes.

A more robust approach overrides the <source lang=apl inline>Wait</syntaxhighlight> method <source lang=apl inline>MyApp</syntaxhighlight> inherited from the <source lang=apl inline>Form</syntaxhighlight> class. We can localise <source lang=apl inline>⎕TRAP</syntaxhighlight> in <source lang=apl inline>Wait</syntaxhighlight>, log the error from the environment in which it occurred, then ensure the stack is cut back only to a point at which we can resume.

<source lang=apl>

   ∇ Wait;⎕TRAP;done
     :Access Public
     ⎕TRAP←⊂(⍳500)'E' '⎕←↑¨⎕SI ⎕LC ⋄ ⎕SIGNAL 911'
     :Repeat
         :Trap 911
             done←0∊⍴⎕BASE.Wait
         :Else
             done←0
         :EndTrap
     :Until done
   ∇

</syntaxhighlight>

Here is a slightly more elaborate version taken from a commercial application. This application's user-interface object needs its error trapping to report what is in its <source lang=apl inline>ThisObj</syntaxhighlight> slot.

<source lang=apl>

   ∇ Wait;⎕TRAP;done
     :Access Public
     ⎕TRAP←⊂(911~⍨⍳1006)'E' '#.SESSION.Log.Error ⎕DM ⋄ ⎕SIGNAL 911'
     :Repeat
         :Trap 911
             done←0∊⍴⎕BASE.Wait
         :Else
             #.SESSION.Log.Record'Error in ',⍕ThisObj
             CursorObj←#.GUI.CURSOR.Default
             #.GUI.Error'System has trapped and logged an error in ',⍕⊃⊃⎕CLASS ThisObj
             done←0
         :EndTrap
     :Until done
   ∇

</syntaxhighlight>

See also

APL development [edit]
Interface SessionTyping glyphs (on Linux) ∙ FontsText editors
Publications IntroductionsLearning resourcesSimple examplesAdvanced examplesMnemonicsISO 8485:1989ISO/IEC 13751:2001A Dictionary of APLCase studiesDocumentation suitesBooksPapersVideosAPL Quote QuadVector journalTerminology (Chinese, German) ∙ Neural networksError trapping with Dyalog APL (in forms)
Sharing code Backwards compatibilityAPLcartAPLTreeAPL-CationDfns workspaceTatinCider
Implementation ResourcesOpen-sourceMagic functionPerformanceAPL hardware
Developers Timeline of corporationsAPL2000DyalogIBMIPSASTSC