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

REBOL 3 Concepts: Functions: Function Attributes

Pending Revision

This document was written for R2 and has yet to be revised for R3.

Function attributes provide control over specific function behaviors, such as the method a function uses to handle errors or to exit. The attributes are an optional block of words within the interface specifications.

There are currently two function attributes: catch and throw.

Error messages typically are displayed when they occur within the function. If the catch attribute is specified, errors that are thrown within the function are caught automatically by the function. The errors are not displayed within the function but at the point where the function was used. This is useful if you are providing a function library (mezzanine functions) and don't want the error to be displayed within your function, but where it was called:

root: func [[catch] num [number!]] [
    if num < 0 [
        throw make error! "only positive numbers"
    ]
    square-root num
]

root 4
2
root -4
**User Error: only positive numbers
**Where: root -4

Notice that in this example, the error occurs where root was called even though the actual error was generated in the body of the function. This is because the catch attribute was used.

Without the catch attribute, the error would occur within the root function:

root: func [num [number!]] [
    square-root num
]
root -4
** Math Error: Positive number required.
** Where: square-root num

The user may not know anything about the internals of the root function. So the error message would be confusing. The user only knows about root, but the error was in square-root.

Do not get the catch attribute mixed up with the catch function. Although they are similar, the catch function can be applied to any block that is evaluated.

The throw attribute allows you to write your own control functions, such as for, foreach, if, loop, and forever, by allowing your functions to pass the return and exit operations. For example, this loop function:

loop-time: func [time block] [
    while [now/time < time] block
]

evaluates a block until a specific time has been reached or passed. This loop can then be used within a function:

do-job: func [job][
    loop-time 10:30 [
        if error? try [page: read http://www.rebol.com]
            [return none]
    ]
    page
]

Now, what happens when the ['return [bad-link:datatypes/none].txt] block is evaluated? Because this block is evaluated by the loop-time function, the return occurs in that function, not in do-job.

This can be prevented with the throw attribute:

loop-time: func [[throw] time block] [
    while [now/time < time] block
]

The throw attribute causes a return or exit that has occurred within the block to be thrown up to the previous level, which is the next function causing do-job to return.


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