What's "normal" and what's an "error"? (Or, for that matter, a "crash"?)
When looking for the best solution to a coding problem, we can be prisoners
of our emotive use of language. Way back in IBM in the 1980s I recall the
end-user of a bespoke app written in APL picking up the phone in fury when
it spat out at her the all-too-familiar APL message:
RANK ERROR
– she thought the coder was being gratuitously offensive.
Stripped of its pejorative connotations, error recovery is just a way of
letting a deeply nested function escape and cut back the function stack –
and to do it in a way that doesn't look to the end-user like a coding
error. Or conversely, treating her to the sight of a raw coding error when
she'd appreciate a polite message geared to her needs and competency.
I use (::) a lot for this purpose. Far from being "ugly" I think it is
clean and respectable, avoiding the need for (…but not precluding) a
cumbersome system of error diagnostics – which then needs debugging in its
own right.
It also establishes a clear separation between "normal" code and
special-case handling (including error recovery), which lets you design the
former and then bolt-on as much of the latter as you need, and no more —
which to my mind (try./catch.) doesn't.
Paste this into a temp script and run it:
————————————————————————————————————————
NB. Use of (::) to escape to the session in a clean and respectable way.
NB. Avoid tainting the escape route with disapproval
NB. by using "general" not "normal" and "special" not "error".
myApp=: general :: special
general=: verb define
general1 y
)
general1=: verb define
NB. nest it deeper
addOne y
)
addOne=: verb define
NB. recognise special cases...
if. y<0 do. @@ end.
if. y>99 do. @@ end.
NB. else handle the general case...
y+1
)
special=: verb define
'myApp: cannot handle the argument: ' , ":y
)
————————————————————————————————————————
Running the app…
myApp 5 NB. handles general case ok
6
myApp _5 NB. rejects y<0
myApp: cannot handle the argument: _5
myApp 100 NB. rejects y>99
myApp: cannot handle the argument: 100
myApp '?' NB. forces a syntax error
myApp: cannot handle the argument: ?
Now, crashing (general) by executing (@@) is not everyone's idea of "clean
and respectable". But worse – you can't tell a deliberate crash from an
accidental one, as (myApp'?') shows.
However instead of (@@) you can signal a quasi-error with your own private
error number, and progressively code just the error diagnostics you need
into verb: (special) to report any bona-fide coding errors you haven't
fixed yet.
NuVoc explains how:
http://code.jsoftware.com/wiki/Vocabulary/ErrorMessages#Defining_your_own_error_conditions
Thus you could redefine (addOne) and (special) like this…
————————————————————————————————————————
addOne=: verb define
NB. recognise special cases...
if. y<0 do. signalErrorNumber 255 end.
if. y>99 do. signalErrorNumber 99 end.
NB. else handle the general case...
y+1
)
special=: verb define
select. latestErrorNumber''
case. 99 do. 'myApp: cannot handle y>99: ' , ":y
case. 255 do. 'myApp: cannot handle y<0: ' , ":y
case. do. latestErrorMessage''
end.
)
signalErrorNumber=: 13!:8
latestErrorNumber=: 13!:11
latestErrorMessage=: 13!:12
————————————————————————————————————————
Now running the app…
myApp 5 NB. handles general case ok
6
myApp _5 NB. rejects y<0
myApp: cannot handle y<0: _5
myApp 100 NB. rejects y>99
myApp: cannot handle y>99: 100
myApp '?' NB. forces a coding error
|domain error: addOne
| y <0
On Sun, Dec 31, 2017 at 4:40 AM, Nick S <[email protected]> wrote:
> You are right about that, Raul. Honestly, I may do so - but I am not 100%
> sure the solving method will work, so I am grafting it in crudely, with
> stacked environments and so forth. If it does work I will do a redesign
> and tie things in tighter, for one thing it would allow me to see that the
> trial placement is causing errors earlier in the process.
> I did discover this: (To summarize - if I use throw. and the try has a
> catcht but not a catch. regular error handling is effective - so I can use
> throws, try's with only catcht's and it won't mess up normal error
> handling, So I need to add a top level catch in the main solve routine and
> a bit more logic. Probably a state flag or two.
>
> broke =: 3 : '1 + y'
> broke 3
> 4
> broke 'x'
> |domain error: broke
> | 1 +y
> trybroke =: 3 : 'try. broke y catcht. ''throw'' end.'
> |control error
> | [0]try. broke y catcht.
> | trybroke=:3 :'try. broke y catcht. 'throw' end.'
> trybroke =: 3 : 'try. broke y catcht. ''throw'' end.'
> trybroke 3
> 4
> trybroke 'x'
> |domain error: broke
> | 1 +y
> trybroke =: 3 : 'try. broke y catcht. ''throw'' catch. ''error'' end.'
> trybroke 3
> 4
> trybroke 'x'
> error
> broke =: 'throw.'
> broke =: 3 : 'throw.'
> trybroke 3
> error
> broke =: 3 : 'throw.'
>
>
> trybroke 3
> throw
> trybroke =: 3 : 'try. broke y catcht. ''throw'' end.'
> trybroke 3
> throw
> broke =: 3 : '1 + y'
> trybroke 3
> 4
> trybroke 'x'
> |domain error: broke
> | 1 +y
>
>
> On Sat, Dec 30, 2017 at 8:27 PM, Raul Miller <[email protected]>
> wrote:
>
> > The exit mechanism, throws, errors and returns are basically your
> options.
> >
> > You can combine them, of course. For example, you can catch a throw
> > and then return. Or you can run a J instance in a separate process and
> > then exit from that and return from the routine that started the
> > process. Or maybe you want to use a stop-on-error script or adverse to
> > regain control -- http://www.jsoftware.com/help/dictionary/dx000.htm
> > or http://www.jsoftware.com/help/dictionary/d312.htm
> >
> > Ultimately... what you're talking about is a bit ugly and whatever you
> > choose is going to have some warts. If you wanted clean, though, you'd
> > redesign and rebuild.
> >
> > Good luck,
> >
> > --
> > Raul
> >
> >
> >
> > On Sat, Dec 30, 2017 at 7:48 PM, Nick S <[email protected]> wrote:
> > > Well, exit'' takes J down completely.
> > >
> > > I have read through most of the foreigns again, and through doc, and I
> > > searched the messages from this forum for a bit. Either I can't find
> the
> > > right search string or it has not been discussed since I have begun
> > > following this. I just can't find an answer.
> > >
> > > I have a deeply embedded function that discovers that it has completed
> > the
> > > task set before it. (This is a continuation of my solitare game
> solver).
> > > I am doing trial solutions - and if everything works. it will declare a
> > > solution and end.
> > >
> > > This function was not part of the initial design. It would be
> > inconvenient
> > > for me to return and then set a flag so that the top level solver code
> > > emits the right messages, although I could do that.
> > >
> > > Instead I was hoping to, from whatever level of recursion I have
> reached
> > is
> > > doing trial solutions, to decide that I have met the burden of "being
> > > done". and simply return to the console prompt, allowing the stack to
> be
> > > thrown away.
> > >
> > > I suppose I could execute the entire thing under a try. and throw back
> to
> > > it.
> > > Is throw the only way to do this? I guess I could just use an uncaught
> > > throw, as:
> > >
> > >
> > > foo =: 3 : 'if. y > 64 do. y throw. else. foo >: y end. '
> > >
> > > foo 1
> > >
> > > $ foo 1
> > >
> > > # foo 1
> > >
> > > Is the answer as simple as an uncaught throw or is there a "right" way?
> > >
> > > I searched for "uncaught throw" and found
> > > uncaught throw. gives no message
> > >
> > > Now it does: error code 35, 'uncaught throw.'
> > >
> > > Henry Rich <http://code.jsoftware.com/wiki/User:Henry_Rich> (talk
> > > <http://code.jsoftware.com/mediawiki/index.php?title=
> > User_talk:Henry_Rich&action=edit&redlink=1>)
> > > 15:06, 4 June 2017 (UTC)
> > >
> > > So that is probably something that I should not use because it will be
> > > fixed, I just don't have it yet. I don't want to mess with the
> debugger.
> > > I guess I could make a master catcher that runs everything but then I
> > have
> > > to pass on errors or I get nothing when I have a bug.
> > >
> > > I'll admit I am being lazy. I am trying to add trial and error to a
> > solver
> > > that works whenever there is enough info in the puzzle specification,
> but
> > > when there is not, the next trick is to try blocks in various
> positions,
> > > and when you get impossible progressions, you can eliminate a space and
> > > then try again. I might be descended through several layers as the
> > > solution is found.
> > > --
> > > Of course I can ride in the carpool lane, officer. Jesus is my
> constant
> > > companion.
> > > ----------------------------------------------------------------------
> > > For information about J forums see http://www.jsoftware.com/forums.htm
> > ----------------------------------------------------------------------
> > For information about J forums see http://www.jsoftware.com/forums.htm
> >
>
>
>
> --
> Of course I can ride in the carpool lane, officer. Jesus is my constant
> companion.
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
>
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm