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

REBOL 3 Guide: Code: Conditional evaluation

This section describes conditional evaluation.

Be sure you know the basics of evaluation from the prior section: code: how code is evaluated.

Contents

What is true?

A conditional expression is one that evaluates to true or false.

10 > 4
true
empty? ""
true
empty? "test"
false

However, in REBOL we allow a true condition to be more than just the value true - almost any other value is accepted as a true value. This allows us to simplify many expressions, but at the slight cost that you must keep the rule in mind.

Here is the rule: any value that is not false and not none is true.

So, these are all considered true:

true
"bob"
0
123
12:30
[a b c]
%file

and, other such values.

C programmers:

Note the zero case! Any integer, even zero, is considered true! (The reason for this will become more clear as you learn more.)

If then

The if function evaluates an expression, and if it is true, evaluates the block that follows.

n: 14
if n > 10 [print "greater than 10"]
greater than 10

Any expression that returns false or none will not evaluate the block. All others will. Therefore, you can use expressions that return other values. Here's a common one:

string: "let's talk about REBOL"
if find string "talk" [print "found"]
found

If the find function succeeds, it returns a string. That's considered a true expression. If find fails, it returns none, a false expression.

Because if is a function it returns a value. For a true condition it returns the result of the block evaluation, or none when false:

n: 10
print if n > 3 ["greater"]
greater
n: 1
print if n > 3 ["greater"]
none

Also, notice that you can pass variables for block arguments:

then-block: [print "greater than 10"]

n: 14
if n > 10 then-block
greater than 10

In fact the block also be the result of some other expression, that returns a block. More on that later.

Either or

The either function is used to evaluate one of two blocks. It's what you use for an if-else type of expression. (REBOL does not use else.)

The either function takes one condition and two blocks:

n: 10
print either n > 20 ["greater"] ["not greater"]
not greater

Any condition that is false or none will evaluate the second block.

And like if, either returns a value, depending on which block it evaluated:

print either n > 20 ["greater"] ["not greater"]
not greater

Also, the block values can be variables, defined earlier or even returned as results from other functions:

then-block: [n - 2]
else-block: [n + 2]

n: 10
print either n > 20 then-block else-block
12

A common mistake

A common mistake is to add a second block to if or forget the second block on either.

These are both wrong, but they may or may not cause a run-time error:

if n > 50 [print "greater"] [print "not greater"] ; extra block!

either age > 50 [print "greater"] ; missing a block!
Watch out!

Such errors can be difficult to find. If you are editing code, and you modify an if or either, be sure to check the expression.

Any and all

The any and all functions are used quite often and let you evaluate multiple conditions in an easy way. The are also more efficient for many types of expressions.

The any function will evaluate a block of expressions until one is true (is not [bad-link:functions/false.txt] or [bad-link:functions/none.txt]). The all function requires that all the expressions are true.

An example of any is:

n: -10
if any [n < 0 n > 100] [print "out of range"]
out of range

And all is:

n: 10
if all [n > 0 n < 100] [print "in range"]
in range

You can see that these are like doing or and and functions, but we call them shortcut functions, because they only evaluate as much as they need.

Here is a very common programming pattern:

name: "Bob"
if all [
    string? name
    not empty? name
    find ["Bob" "Ned" "Sam"] name
][
    print "found name"
]
found name

Also, any and and return useful results. When successful, they return a value. When they fail, they return none.

name: "Sam"
print all [
    string? name
    spot: find ["Bob" "Ned" "Sam"] name
    index? spot
]
3

This example also shows how all is used to replace an if without adding extra code.

See expressions: conditionals for more details.

Case of many

In many languages, it is common to stack if and else statements in a pattern like:

if ...
else if ...
else if ...
else ...

In REBOL, you can do that with either, but generally we avoid it and use case instead.

It has the general form:

case [
    condition1 [expression1]
    condition2 [expression2]
    ...
]

For example:

n: 10
case [
    n > 100 [print "too large"]
    n > 20  [print "still too large"]
    n < 0   [print "too small"]
    true    [print "in range"]
]
in range

Note the use of true for the last case, evaluated when all the others fail.

And, because case is a function that returns a result, the above example could be written:

n: 10
print case [
    n > 100 ["too large"]
    n > 20  ["still too large"]
    n < 0   ["too small"]
    true    ["in range"]
]
in range

It turns out that case does not require blocks for simple values, so you can further reduce this down to:

n: 10
print case [
    n > 100 "too large"
    n > 20  "still too large"
    n < 0   "too small"
    true    "in range"
]
in range

The case function also has a refinement that lets you evaluate all the conditional expressions. See the function description for more detail.

Switch on value

The switch function finds a matching value and evaluates its related block.

The matched value can be of any datatype. Simple integers for example:

n: 22
switch n [
    11 [print "here"]
    22 [print "there"]
    33 [print "everywhere"]
]
there

You can also tell switch to evaluate a default block, if no values are matched:

n: 123
switch/default n [
    11 [print "here"]
    22 [print "there"]
    33 [print "everywhere"]
][
    print "nowhere"
]
nowhere

There are many uses for switch as shown here:

name: "Sam"
switch n [
    "Bob" [print "here"]
    "Sam" [print "there"]
    "Ted" [print "everywhere"]
]
there
html-tag: <title>
print switch html-tag [
    <pre>   ["preformatted text"]
    <title> ["page title"]
    <li>    ["bulleted list item"]
]
page title
time: 12:30
switch time [
     8:00 [send wendy@domain.dom "Hey, get up"]
    12:30 [send cindy@dom.dom "Join me for lunch."]
    16:00 [send group@every.dom "Dinner anyone?"]
]

Note that the switch block is not evaluated so if it contains expressions, you will need to use reduce first:

n: 22
switch n reduce [
    11 [print "here"]
    11 * 2 [print "there"]
    11 * 3 [print "everywhere"]
]
there

If you want to use switch on datatypes, use this method:

n: 22
switch type?/word n [
    integer! [print "integer"]
    decimal! [print "decimal"]
    time!    [print "time"
]

See the type? function for details.

Also, like other functions, switch returns the value of the block it has evaluated.

Conditional loops

Conditional loops, such as while and until, are covered in the code: repeated evaluation (loops) section that follows.


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