Passing Single Values and Blocks to Functions

Author: Gregg Irwin
Return to REBOL Cookbook

Here is a tip for creating functions that allow both a single value or a block of values as an argument. For example if you create a function called touch, you may want to allow:

    touch %file1
    touch [%file1 %file2 %file3]

In REBOL a function interface lets you specify more than one datatype for a parameter, and you can also use REBOL pseudotypes (like any-block!) to give you even more flexibility.

    touch: func [files [file! any-block!]] [ ]

This function will accept a file!, block!, hash!, list!, or paren! value (the last four all fall under the any-block! type).

When you pass a block to the function, your code can iterate over it with functions like FOREACH.

    foreach file files [
        set-modes file [modification-date: time]

But, if a single file is passed, the code above will fail. The FOREACH needs a series of files, not a single file.

The simple solution is to put the single file into a block before doing the FOREACH. The COMPOSE function is a handy way to do that:

    touch: func [files [file! any-block!] time] [
        foreach file compose [(files)] [
            set-modes file [modification-date: time]

So, now you can create a function with a flexible interface but keep it simple without special case handling for different datatypes.

Of course, here we assume that a block passed to us contains file! values and that the files aren't read-only in order for SET-MODES to work.

Why This Works

The COMPOSE function is able to convert a single value to a block containing that value, but not affect blocks that are passed in. This lets your code operate as if a block was always passed in.

You can see in the console what COMPOSE does in this case:

    >> compose [(%test.txt)]
    == [%test.txt]

    >> compose [([%test.txt test-2.txt])]
    == [%test.txt test-2.txt]

Of course, this is not the only purpose of COMPOSE. See the REBOL Dictionary for more information.

2006 REBOL Technologies REBOL.com REBOL.net