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

REBOL 3 Guide: Code: How code is evaluated

Left to right and right to left.


Evaluation sequence

In code: evaluating blocks you learned that code is held in data blocks that get directly evaluated.

In general, expressions are evaluated from left to right; however, within each expression evaluation occurs from right to left.

Take this example:

print length? join "exam" "ple"

The print and length? functions require one argument. The join function requires two arguments. You can divide the line into separate sections that are each evaluated.

We start with:

print length? join "exam" "ple

which evaluates to:

print length? "example"

and finally to:

print 7

This is called the substitution method of understanding evaluation. It is handy to remember.

What, no expression separators?

For programmers who know other languages, it may seem odd that REBOL combines these into a single expression. We have no need for extra parentheses, commas, or other punctuation.

All we can say is don't worry! We've found it works quite well. Your brain is tuned for parsing sentences, and it will parse REBOL expressions equally well, once you get used to it.

Multiple expressions

Multiple expressions are written in the same way. You don't need separators, but we often will put new expressions on a separate line to make them more readable.

Here are three separate expressions:

print "reading web page..."
data: read
print length? data

You could have written all these on one line, but the results would be the same.

How do you know where each expression begins and ends? It is determined by the arity (the number of arguments) required by each function. For example, print only takes one argument. Once it has that argument, evaluation advances to the next expression.

If you are not sure how many arguments a function requires, use help on it. However, for the most common functions, it won't take long for you to memorize them.

Multiple results

As mentioned in code: evaluating blocks a block returns a result. However, there are times when we want multiple results from a block.

Consider what happens when you write:

print ["results:" 1 + 2 3 * 4]
results: 3 12

Here the block passed to print is returning more than just one value.

As you can see below, the block result is no longer the same thing as:

do ["results:" 1 + 2 3 * 4]

When you need multiple results, rather than do, use reduce instead:

reduce ["results:" 1 + 2 3 * 4]
["results:" 3 12]

Notice that the substitution method of evaluating your results remains the same, but you keep all results in a block.

This is a very important concept in REBOL. It allows you to to pass, store, and return multiple values in a similar way to how you would handle a single value.

Operator precedence

To make mathematical expressions easier to read, the language supports infix operators like plus, minus, multiply, divide, and a few others.

Operators are an exception to the above rule. Take the expression:

print 1 + 2

This is evaluated as:

print (1 + 2)

not as:

(print 1) + 2

Operators take precedence over normal functions. However, note that all operators have the same precedence. Operators are applied from left to right.

Take this example:

print 1 + 2 * 3 + 4 * 5

It evaluates left to right, using the substitution method:

print 3 * 3 + 4 * 5

print 9 + 4 * 5

print 13 * 5

print 65

Changing the order of the values changes the result:

print 2 * 3 + 1 + 4 * 5

So, it's just left-to-right, and operators take precedence over functions.

Looking at:

print 10 * sine 30 + 60

It evaluates to:

print 10 * sine 90
print 10 * 1.0
print 10.0
Linear precedence

If you program in other languages, you will need to remember this difference.

We've found that for most expressions, linear precedence works as well or better than multilevel precedence, and you don't have to memorize all the precedence rules (which once you add comparisons and logic can become quite complex and few people remember them.)


Parentheses can be used to control the order of evaluation:

(2 + 3) * (10 - 5)

That is the same as:

2 + 3 * (10 - 5)

When using length?, this is a common case:

if (length? "a string of chars") > 10 [print "ok"]

Of course, you can reorder that line as:

if 10 <= length? "a string of chars" [print "ok"]

But, maybe that does not read as well, so another alternative is to use the greater? function instead of the operator:

if greater? length? "a string of chars" 10 [print "ok"]

  TOC < Back Next > - WIP Wiki Feedback Admin