There are some limitations associated with functions, the ARG() function, and the PARSE ARG and EXPOSE instructions. To get around these limitations, Reginald offers the USE ARG function. But before we talk about USE ARG, let's examine those limitations.

One limitation is that a function can return only one value. Let's assume that we wish to write a function (named GetFileInfo) that is passed a filename, and it will return several pieces of information about that file including its size, last modified date, creation date, and full path name. If we wanted to return all this information to some caller, one technique we could do is to just append all the information into one string, and return that as our value, for example:

/* Here's our GetFileInfo function */
GetFileInfo:

/* Assume that we call some functions to get the information
 * about the file, and we have saved the file's creation
 * date in the variable named "created", the last modified
 * date in "modified", the size in "size", and the full path
 * name in "path".
 */

/* Return the 3 pieces of information separated by a space
 * with the creation date first, modified date second,
 * size third, and full path name last.
 */
RETURN created modified size path
This works, but it has several drawbacks. First of all, if the caller wants to examine those separate pieces, he has to pull them apart again. It's inefficient for our function to append this information together if the caller needs to pull it apart again. He can use a PARSE VALUE to pull it apart as so:
/* Call GetFileInfo and parse the results into separate variables */
PARSE VALUE GetFileInfo('MyFileName') WITH created modified size path

But if any of the first pieces of information (ie, created, modified, or size) have spaces in them, then this is going to be a hassle for him since PARSE VALUE normally breaks a string into individual pieces at spaces. He will have to try to parse by offsets or search strings. Obviously, this is not a good approach to returning several pieces of information.

Another technique we can do is to simply leave the individual pieces of data stored in some variables for him. For example, we'll simply write a subroutine that sets the variables named "created", "modified", "size", and "path". So when we return, the caller just accesses those specific variables. This works. But what if the caller wants to call GetFileInfo() upon dozens of files and collect the information for all of them? Now he has to do a lot of copying of data, like so:

/* Call GetFileInfo to get info on the first file */
GetFileInfo('MyFirstFileName')

/* Now save the information to a more permanent set of variables */
FileCreated.1 = created
FileModified.1 = modified
FileSize.1 = size
FilePath.1 = path

/* Call GetFileInfo to get info on the second file */
GetFileInfo('MySecondFileName')

/* Now save the information to a more permanent set of variables */
FileCreated.2 = created
FileModified.2 = modified
FileSize.2 = size
FilePath.2 = path

/* Call GetFileInfo to get info on the third file */
GetFileInfo('MyThirdFileName')

/* And yet more copying... */
FileCreated.3 = created
FileModified.3 = modified
FileSize.3 = size
FilePath.3 = path
Obviously, this technique is inefficient too. Plus, we've forced the caller to use certain named variables in his use of GetFileInfo. GetFileInfo isn't very generic because it forces the caller to use the variables named "created", "modified", "size", and "path". We could redesign GetFileInfo to be passed the names of the variables that the caller wants us to save the information in. For example, let's say that we redesign GetFileInfo to be passed (in addition to the filename) the names of the four variables where he wants the pieces of information saved. We could then use the VALUE() built-in function to set the variables' values. So the caller may call GetFileInfo as so:
/* Call GetFileInfo to get info on the first file and store in these variables */
GetFileInfo('MyFirstFileName', FileCreated.1, FileModified.1, FileSize.1, FilePath.1)

/* Call GetFileInfo to get info on the second file and store in these variables */
GetFileInfo('MySecondFileName', FileCreated.2, FileModified.2, FileSize.2, FilePath.2)

/* Call GetFileInfo to get info on the third file and store in these variables */
GetFileInfo('MyThirdFileName', FileCreated.3, FileModified.3, FileSize.3, FilePath.3)
And GetFileInfo can do this:
/* Here's our GetFileInfo subroutine */
GetFileInfo:

/* Assume that we call some functions to get the information
 * about the file, and we have saved the file's creation
 * date in the variable named "created", the last modified
 * date in "modified", the size in "size", and the full path
 * name in "path".
 */

/* Save "created" in the caller's variable name he passed as
 * the second arg
 */
VALUE(ARG(2), created)

/* Save "modified" in the caller's variable name he passed as
 * the third arg
 */
VALUE(ARG(3), modified)

/* Save "size" in the caller's variable name he passed as
 * the fourth arg
 */
VALUE(ARG(4), size)

/* Save "path" in the caller's variable name he passed as
 * the last arg
 */
VALUE(ARG(5), path)
This is little better. It makes GetFileInfo more generic, and makes less work for the caller. But what happens if we put a PROCEDURE on GetFileInfo? Now we've broken our approach because VALUE() doesn't work across PROCEDURE boundaries. The call:
VALUE(ARG(2), created)
will set the FileCreated.1 variable that exists only in GetFileInfo -- not the FileCreated.1 variable that exists in the caller. They are two different variables across a PROCEDURE boundary.

For this reason, the USE ARG instruction can be useful in GetFileInfo. USE ARG allows you to utilize your own variable name when you grab some variable that the caller passed to your subroutine. And any modification you make to your own variable is reflected in the caller's respective variable, even across a PROCEDURE boundary. Let's take an example. Here's how we may notate the USE ARG instruction:

GetFileInfo: PROCEDURE

USE ARG filename, created, modified, size, path

/* Now when we store some value in "created", it also
 * gets stored in whatever variable the caller used
 * as the second arg to GetFileInfo. Whatever we store
 * in "modified" also gets stored in whatever variable
 * the caller used as the third arg to GetFileInfo.
 * Whatever we store in "size" also gets stored in whatever
 * variable the caller used as the fourth arg to GetFileInfo.
 * And whatever we store in "path" also gets stored in
 * whatever variable the caller used as the fifth arg to
 * GetFileInfo.
 */

RETURN
When you utilize USE ARG, you are setting up a direct link between a variable of your own name, and whatever variable was used by the caller to pass some value to your function. So now the caller can do the following and it will work across a PROCEDURE boundary:
/* Call GetFileInfo to get info on the first file and store in these variables */
GetFileInfo('MyFirstFileName', FileCreated.1, FileModified.1, FileSize.1, FilePath.1)

GetFileInfo: PROCEDURE
USE ARG filename, created, modified, size, path

/* This also sets FileCreated.1 to 0 */
created = 0
/* This also sets FileModified.1 to "Jan 6, 2003" */
modified = "Jan 6, 2003"

RETURN
And GetFileInfo is now generic. You do not need to know exactly what variable names the caller has specifically used to pass values to you. With USE ARG, you simply establish a direct link with whatever variable names he has used, using your own choice of names for those variables.

USE ARG works both ways as well. When you establish a direct link, you also gain access to whatever the caller set for the value of the variable he passed. Consider a case of where the caller sets the value of the variable MyVariable and then calls MySub, passing the value of MyVariable:

/* Set MyVariable to "hello" and call MySub */
MyVariable = "hello"
MySub(MyVariable)
Now, consider this:
MySub:
/* Say the arg passed to me. It will display "hello" */
SAY ARG(1)
RETURN
Here's how you do the same thing with USE ARG:
MySub:
/* Establish a direct link to whatever variable he used for the
 * first arg (ie, MyVariable), and give it the name "value"
 */
USE ARG value

/* Say "value". It will display "hello" */
SAY value

/* If we now change "value", that also changes "MyVariable" */

RETURN
So what about the first arg the caller passed to GetFileInfo? He didn't use a variable to pass that arg. He passed it as the literal string 'MyFirstFileName'. That's not a variable name. It's a string. What happens in GetFileInfo at the USE ARG instruction?
USE ARG filename, created, modified, size, path
What exactly happens with the variable "filename"? Well, since the caller did not use a variable to pass the first argument, then filename is not directly linked to any other variable. "filename" is simply its own variable, and does not affect any other, differently named variable. And what is filename's value? It is the literal string "MyFirstFileName" since that is what the caller passed. So for arguments that are passed without using a variable, then USE ARG is the same thing as PARSE ARG (ie, there is no direct link made to any other variable).

If you don't care about establishing a direct link, then you can just omit any variable name before a comma. For example, here we make a direct link with the first and third args passed to us, but not the second arg. We use the variable name "one" for our direct link to whatever variable was passed first, and "three" for whatever variable was passed third.

USE ARG one, , three
USE ARG can also establish a link to a stem variable. Here the caller initializes some compound variable and then passes the name of his stem to the subroutine. The subroutine makes a direct link to that stem, using its own stem name of "MyStem.".
/* Use the stem name "MyVar." to pass the first arg */
MyVar.1 = "Hello"
MySub(MyVar.)
RETURN

MySub:
/* Establish a direct link to whatever variable the caller passed
 * as the first arg, and use the stem name of "MyStem."
 */
USE ARG MyStem.

/* This says "Hello" */
SAY MyStem.1

/* Now let's set MyStem.2 which also sets MyVar.2 */
MyStem.2 = 100

RETURN
Incidentally, USE ARG works with or without the PROCEDURE keyword. So you can make your functions generic in regards to variable names regardless of whether you actually use PROCEDURE to protect variables. You'll notice in the example above that PROCEDURE was not used. When MySub returns, the direct link is broken between MyStem. and MyVar. nevertheless.

USE ARG also works between two scripts. If you copy MySub to a separate script and call it from another script, then "value" will still be a direct link to whatever variable the calling script passed as the first arg.

USE ARG does have one limitation. The USE ARG variable must be either a simple or a stem variable name. It cannot be a compound. For example, you cannot do this:

USE ARG MyStem.MyTail

USE ARG is especially handy if you need to return a very large amount of data to a caller. By directly linking with the caller's variable, you not only make your subroutine generic with regard to variables' names, but also eliminate using any scheme where data needs to be returned indirectly such as on the stack (and thereby perhaps cause extra copies of that large amount of data to be internally processed).