REBOL 3 Docs | Guide | Concepts | Functions | Datatypes | Errors |
TOC < Back Next > | Updated: 12-Apr-2009 Edit History |
This section describes conditional evaluation.
Be sure you know the basics of evaluation from the prior section: code: how code is evaluated.
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.
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.
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 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!
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.
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.
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, 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 |