Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] Re: Beginner's questions on REBOL/Core and REBOL/View

From: joel:neely:fedex at: 11-Sep-2002 22:43

Hi, Sunanda, and all, The problem with small examples is that they're... small. This sometimes makes things look trivial that really aren't, IMHO. However, I'm interested in your opinions of the constructive suggestions near the end... [SunandaDH--aol--com] wrote:
> ... Rebol gives far too little away when there is an error -- > maybe Carl S doesn't make stupid coding errors like the rest > of us. > > Let me modify your code to have a bug in it ... And run it. > We get: > > ** Math Error: Attempt to divide by zero > ** Near: print b: 2 / 0 >
...
> Better context information *is* in there somewhere -- try this: > the same error in a VID action facet: > > unview/all > view layout [ > button "click me" > [
...
> ] > ] > > This fails in an easier to find way -- better context > information: > > ** Math Error: Attempt to divide by zero > ** Where: func [face value][ > a: [print b: 2 / 0] > c: [2 / 0] > d: append a c > insert d first [print] > do d > ] > ** Near: print b: 2 / 0 >
Note that this shows quite a bit of stuff that appears nowhere in our source code: the func [face value][ bit, as well as the block to which A is being set. This would also be likely to confuse the typical beginner IMHO. However... Let's try that in Core (or at least the moral equivalent...)
>> crash: func [/local a c d] [
[ a: copy [b:] [ c: [2 / 0] [ d: append a c [ insert d first [print] [ do d [ ]
>> crash
** Math Error: Attempt to divide by zero ** Where: crash ** Near: print b: 2 / 0 Notice that middle line ** Where: crash which actually tells us where to look for the expression which caused the math error. If we define and use reasonably small functions, this narrows our scope quite a bit. Going further, we can actually reproduce your more verbose case, as follows:
>> do func [/local a c d] [
[ a: copy [b:] [ c: [2 / 0] [ d: append a c [ insert d first [print] [ do d [ ] ** Math Error: Attempt to divide by zero ** Where: func [/local a c d][ a: copy [b:] c: [2 / 0] d: append a c insert d first [print] do d ] It appears that REBOL is trying (in all cases???) to show us the exact structure/expression being evaluated when the math error occurred. It's just that this second case involves a larger expression, perhaps. While I might agree that more detailed information would be helpful, I still maintain that it doesn't relate to "source line" in many cases. I haven't had time to play with the preprocessor, but I suspect the concept of "source file" becomes even more obscured when we #INCLUDE source from multiple places (especially when nested...) If we change the example just a bit more, we can get a case for which source file concepts just don't apply at all. crash-setup: func [i [integer!] j [integer!]] [ append copy [print] reduce [i to-word "/" j] ] random-range: func [dn [integer!] up [integer!]] [ (random up - dn + 1) + dn - 1 ] crash-prep: func [ n [integer!] lo [integer!] hi [integer!] /local result ][ result: make block! n loop n [ append/only result crash-setup random-range lo hi random-range lo hi ] ] crash-wrapper: func [ n [integer!] bottom [integer!] top [integer!] ][ foreach item crash-prep n bottom top [ do item ] ] crash-wrapper 20 0 5 Evaluating the above yields a nice puzzle: ...
>> crash-wrapper 20 0 5
1 4 0 0 3 1.5 0.333333333333333 1.66666666666667 5 1.5 0.5 2 2.5 1.25 0.333333333333333 ** Math Error: Attempt to divide by zero ** Where: crash-wrapper ** Near: print 4 / 0 My first question is this: What more could REBOL tell us at this point? We're told that the problem occurred during the evaluation of CRASH-WRAPPER, but the body of that function has little to do with the actual expression being evaluated at the point of error. My second question is: How much responsibility do I have as the programmer for detecting and managing errors that may arise during evaluation? REBOL is a very powerful language, but with increased power must come increased responsibility. For example, I could have done some more work to handle errors myself: crash-wrapper2: func [ n [integer!] bottom [integer!] top [integer!] /local risky-blocks ][ foreach item risky-blocks: crash-prep n bottom top [ if error? try [ do item ][ print [ "Error DOing" mold item newline "within" mold risky-blocks ] halt ] ] ] crash-wrapper2 20 0 5 which certainly gives me more context to think about:
>> crash-wrapper2 20 0 5
3 4 5 0 Error DOing [print 4 / 0] within [[print 3 / 1] [print 4 / 1] [print 5 / 1] [print 0 / 1] [print 4 / 0] [print 2 / 3] [print 1 / 0] [print 3 / 4] [print 5 / 3] [print 2 / 2] [print 3 / 3] [print 1 / 2] [print 4 / 2] [print 3 / 2] [print 4 / 5] [print 0 / 4] [print 0 / 1] [print 4 / 3] [print 4 / 5] [print 1 / 5]] Now let me suggest a couple of possibilities: 1) Could we (the list community) describe any additional context information which RT might be able to add to error messages? For example: I suspect that REBOL internally has some sort of representation for all expressions pending evaluation (the moral equivalent of a "stack", for example). Would it be useful/feasible for an uncaught error to dump some portion of that information to the console? Having a more thorough view of what was going on might help the programmer locate and diagnose an error, but we might want some way to control the amount of information displayed (have you ever seen a Java stack trace, for example... ;-) such as limiting the number of levels to be displayed by setting a system variable. 2) Could we (the list community) define "safe" equivalents to some of the more common error-prone operations (e.g. DO, FUNC, ...) so that one could write and test code with the training wheels on? For example: A paranoid SAFE-DO accepting a block or function as its argument could check for errors during evaluation and dump the block or function to the console if something went wrong. A SAFE-FUNC could wrap its argument in a try block to dump the arguments to the console in case of an error. I could even imagine a SET-SAFE and SET-UNSAFE word pair that would redefine DO and FUNC and etc. to be the checked or un- checked versions, so that the same source could admit both checked (but slower) and unchecked (and faster) evaluations. -jn- -- ; Joel Neely joeldotneelyatfedexdotcom REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] { | e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]