REBOL 3 Docs Guide Concepts Functions Datatypes Errors
  TOC < Back Next >   Updated: 20-Oct-2009 Edit History  

REBOL 3 Guide: Code: Debugging tips

Scripts don't always work the way you want. This section helps you to figure out why, and understand some common problems that can occur.

Contents

Common debugging methods

Many years of debugging REBOL code have shown us some of the best ways to debug code. Here are the main ideas.

Print

Quite often, you can simply insert a print to see what your code is doing:

data: copy "test"
loop 3 [print append data random 10]
test3
test38
test382

The ?? function

The ?? function will print the variable name, followed by its value.

a: 10
?? a
a: 10

In addition, it also returns the result, so it can be inserted inline with code:

b: 20
c: a + ?? b
b: 20

If a block is provided as the argument, then each variable and value will be shown:

?? [a b]
a: 10  b: 20

Probing code and data

The probe function will mold a value into source format and display it. It also returns the value as a result.

word: 'here
if probe find [where here there] word []
[here there]

Unlike print, probe does not evaluate the contents of blocks.

probe [1 + 2]
[1 + 2]
print [2 + 2]
3

Trace

If you really need to know what's going on, you can use trace.

Use secure [debug allow] to allow security for debug (used in trace), or type secure help for more information.

You can specify a number of levels to trace

trace 3  ; only trace top three levels

or you can trace everything:

trace on

To disable trace

trace off

The output of trace is very detailed.

Tracing:

print 123
 1: print : native! [value]
 2: 123
    --> print
123
<-- print => unset!

The ==> indicates entry into a function, and <== is the return, with the return value following it.

Understanding error messages

Although we try to make error messages clear, new users may still find them to be frustrating until you understand REBOL at a deeper level.

This example shows the general format of error messages:

either abc [this] [that]
** Script error: abc has no value
** Where: either catch case applier do
** Near: either abc [this] [that]

The first line tells you the general type of error (script error) and provides a few specifics (abc has no value, it is undefined.)

The second line provides the back-trace of functions that were called before the error occurred. The first name is where the error happened. Some of these are functions in your code; others are system functions that called your code.

The third line shows you the code where the error happened. This is an approximate location, because the error may span several values.

More on the details of errors can be found in the errors section.

Common mistakes

Here we point out some of the most common mistakes users make in their code.

Missing brackets or quotes

If you miss a beginning or ending bracket, parenthesis, or quote, when you load the code, you'll see an error message.

For example, if the test.r file is missing its final bracket, you will see this error message:

Evaluating: test.r
** Syntax error: missing "]" at "end-of-script"
** Where: to unless either if load either either do begin do
** Near: (line 3) loop 3 [

The system will attempt to tell you where the problem started, or the matching position for the missing item. However, they can be difficult to find.

If this is a common problem for you, we suggest that you use a code editor that includes a feature for finding matching brackets, braces, and parentheses. For example the VI(M) editor on Linux or XCode on OSX.

Missing arguments

Don't forget to provide all required arguments to each function.

For example, either takes three arguments as shown with here:

? either
USAGE:
    EITHER condition true-block false-block

The code below forgets to provide the third argument, and you see an error:

either a > 10 [a: 1]
print "done"
** Script error: either does not allow unset! for its false-block argument

This error occurs because print returns unset!, which is then passed to either as its second block. That's not valid, and the error occurs.

If you're not sure about the number of arguments, use help to check. You can also use this technique: enclose the problematic expression in a do block.

For example, this will better show an error:

do [ either cond [a: 1] ]
** Script error: either is missing its false-block argument

Extra arguments ignored

If you provide too many arguments, they may be ignored.

For example, the if takes two arguments as shown with here:

? if
USAGE:
    IF condition then-block

If you write:

if a > 10 [a: 1] [b: 2]

The second block is never used, because if does not require it. Although it does not cause an error, your code will not produce the correct results when the if condition is false.

Conditional values other than TRUE and FALSE

Conditional functions provide a shortcut that lets you use values other than logic! as their condition. This done quite often.

In such cases, the condition is only false when it returns false or none!, and they are true when they return any other value.

Below, all of the conditional expressions act like true, even the zero and empty block values.

if true [print "yep"]
yep
if 1 [print "yep"]
yep
if 0 [print "yep"]  ; C programmers - watch out!
yep
if [] [print "yep"]
yep

Here the expressions are false :

if false [print "yep"]

if none [print "yep"]

So, be sure never to enclose the conditional in a block. The block is not evaluated, it just acts like a value, which will be TRUE:

if [false] [print "yep"]
yep

The blocks act like true is simple. This style of coding is used quite often:

if find block item [print "found"]

This is an example of two functions (if and find) being "compounded" together. Let's break that compound set of functions down.

When the find function finds the item, it turns a block! series (at the location of the item). If it fails to find the item, it returns none.

When find block item is resolved to a value, it then becomes the condition argument for the if function, and [print "found"] will become the then-block argument.

The use of compound functions is one of the strengths of Rebol. It is easier and more efficient to code that way than to use temporary arguments like this:

temp: find block item
if temp [print "found"]


  TOC < Back Next > REBOL.com - WIP Wiki Feedback Admin