|REBOL 3 Docs||Guide||Concepts||Functions||Datatypes||Errors|
|TOC < Back Next >||Updated: 8-Mar-2009 Edit History|
The way function arguments are evaluated dictates the general order of words and values in the language. This section goes into more detail on how functions are evaluated.
Functions receive arguments and return results. Most functions require one or more arguments; although, some functions, such as now (current date and time), do not require any arguments.
The arguments that are supplied to a function are processed by the interpreter and then passed to the function. Arguments are processed in the same way, regardless of the type of function called, be it a native function, operator, user-defined function, or otherwise. For example, the [bad-link:functions/send.txt] function expects two arguments:
friend: firstname.lastname@example.org message: "message in a bottle" send friend message
The word friend is first evaluated and its value (''email@example.com ) is provided as the first argument to [bad-link:functions/send.txt]. Next, the word message is evaluated, and its value becomes the second argument. Think of the values of the friend and message variables as being substituted into the line before [bad-link:functions/send.txt] is done:
send firstname.lastname@example.org "message in a bottle"
If you provide too few arguments to a function, an error message is returned. For example, the send function expects two arguments and if you send one, an error is returned
send friend ** Script Error: send is missing its message argument. ** Where: send friend
If too many arguments are provided, the extra values are ignored.
send friend message "urgent"
In the previous example, [bad-link:functions/send.txt] already has two arguments, so the string, which is the third argument, is ignored. Notice that no error message occurs. In this case, there were no functions expecting the third argument. However, in some cases the third argument may belong to another function that was evaluated before [bad-link:functions/send.txt].
Arguments to a function are evaluated from left to right. This order is followed even when the arguments themselves are functions. For example, if you write:
send friend detab copy message
the second argument must be computed by evaluating the detab function and the copy function. The result of the copy will be passed to detab, and the result of detab will be passed to [bad-link:functions/send.txt]. In the previous example, the copy function is taking a single argument, the message, and returns a copy of it. The copied message is passed to the detab function, which removes the tab characters and returns the detabbed message, which is passed to the [bad-link:functions/send.txt] function. Notice how the results of functions flow from right to left as the expression is evaluated.
The evaluation that is happening here can be shown by using parentheses to clarify what is evaluated first. (However, the parentheses are not required, and actually slow down the evaluation slightly.)
send friend (detab (copy message))
The cascading effect of results passed to functions is quite useful. Here is an example that uses insert twice within the same expression:
file: %image insert tail insert file %graphics/ %.jpg print file graphics/image.jpg
In the following example, a directory name and a suffix are added to the base file name. Parentheses can be used to clarify the order of evaluation:
insert (tail (insert file %graphics/)) %.jpg
Functions usually require arguments of a specific datatype. For example, the first argument to the [bad-link:functions/send.txt] function can only be an email address or block of email addresses. Any other type of value will produce an error:
send 1234 "numbers" ** Script Error: send expected address argument of type: email block. ** Where: send 1234 "numbers"
In the previous example, the error message is telling you that the address argument of the [bad-link:functions/send.txt] function needs to be either an email address or a block.
A quick way to find out what types of arguments are accepted by a function is to type the following at the console prompt:
help send USAGE: SEND address message /only /header header-obj DESCRIPTION: Send a message to an address (or block of addresses) SEND is a function value. ARGUMENTS: address -- An address or block of addresses (Type: email block) message -- Text of message. First line is subject. (Type: any) REFINEMENTS: /only -- Send only one message to multiple addresses /header -- Supply your own custom header header-obj -- The header to use (Type: object)
The ARGUMENTS section indicates the datatype of each argument. Notice that the second argument can be of any datatype. So, it is valid to write:
send email@example.com $1000.00
A refinement specifies a variation in the normal evaluation of a function. Refinements also allow optional arguments to be provided. Refinements are available for both native and user-defined functions.
Refinements are specified by following the function name with a forward slash (/) and a refinement name. For instance:
copy/part (copy just part of a string) find/tail (return the tail of the match) load/markup (return XML/HTML tags and strings)
Functions can also include multiple refinements:
find/case/tail (match case and return tail) insert/only/dup (insert entire block multiple times)
string: "no time like the present" print copy string no time like the present
Using the /part refinement, copy returns part of the string:
print copy/part string 7 no time
In the previous example, the /part refinement specifies that only seven characters of the string are copied.
To review what refinements are allowed on a function such as copy, use online help:
help copy USAGE: COPY value /part range /deep DESCRIPTION: Returns a copy of a value. COPY is an action value. ARGUMENTS: value -- Usually a series (Type: series port bitset) REFINEMENTS: /part -- Limits to a given length or position. range -- (Type: number series port) /deep -- Also copies series values within the block.
Notice that the /part refinement requires an additional argument. Not all refinements require additional arguments. For example, the /deep refinement specifies that copy make copies of all its sub-blocks. No other arguments are required.
When multiple refinements are used with a function, the order of the extra arguments is determined by the order in which the refinements are specified. For example:
str: "test" insert/dup/part str "this one" 4 5 print str this this this this test
Reversing the order of the /dup and /part refinement changes the order of the arguments. You can see the difference:
str: "test" insert/part/dup str "this one" 4 5 print str thisthisthisthisthistest
The refinements indicate the order of the arguments.
The previous examples describe how functions return values when they are evaluated. Sometimes, however, you want to obtain the function as a value, not the value it returns. This can be done by preceding the function name with a colon or using the get function. For example, to set a word, pr, to the print function, you would write:
You could also write:
pr: get `print
Now pr is equivalent to the print function:
pr "this is a test" this is a test
|TOC < Back Next >||REBOL.com - WIP Wiki||Feedback Admin|