Yazoo ---> Online Help Docs ---> Yazoo scripting ---> Functions

Function arguments

It's hard to go any further without first confessing to a well-intended white lie that we made in the last section. It happened when we were explaining why print() only displayed the second return value of SwapDigits(). We wrote that print() evaluated both function calls before printing anything --- all well and good. But, we were fibbing a little when we said that functions always evaluate all of their arguments before running their own codes. The true story is that an ordinary C-style argument list will, yes, evaluate entirely before the function begins to run; but if there is a code marker or semicolon present inside the argument list, any arguments that follow will not be evaluated until the function explicitly `runs' them.

That last was probably a pretty mysterious statement; let's show what we mean with an example.


    PrintArgs :: {
       code
       
       print("Before running args: ", args)
       args()
       print("\nAfterwards: ", args)
    }
   

Then we call our function in the following way:


    PrintArgs( 0.3, " 4", code, " word ", 10 )
   

The output is:


    Before running args: 0.3 4
    Afterwards: 0.3 4 word 10
   

Arguments before the code marker evaluate before the function executes, but arguments following the code marker evaluate only when the function calls args().

The part of the argument list preceding the code marker looks a little bit like a constructor, because it dictates how the args set is first defined. But the rest of the arguments are almost analogous to the executable part of a function, because they are expressed by the peculiar args() call. There turns out to be a closer analogy with functions than we might first suspect -- because we can write in all sorts of executable commands besides just tokens, after (or before!) the argument-list's code marker.


    > PrintArgs( 1, code, print("\nRunning args..."), " ", 2 )
   
    Before running args: 1
    Running args...
    Afterwards: 1 2
   

In fact, just about the only code that may not work out quite as expected inside the arguments is a function or variable definition. The fact is that we can define variables and functions inside function arguments, and they will indeed appear in args[], but they will not appear anywhere else in the program. The explanation for this anomaly comes out of the discussion of Chapter 4.

Let's try to push the args-function analogy to the breaking point. Who knows --- if we can run the args list, maybe we can also pass it parameters? Suppose we change the args() line in PrintArgs() to:


    PrintArgs :: {
       ...
       args(9)
       ...
    }
   

We tweak our function call appropriately, and get the following output:


    > PrintArgs( 1, code, print("\n'args' was passed ", args[1]), " ", args[1] )
   
    Before running args: 1
    'args' was passed 9
    Afterwards: 1 9
   

It is important to understand that, in this last example, the `args' keyword referred to one of two different things depending on where it was used. Before the code marker of PrintArgs()'s arguments, args was whatever it had been earlier. Within the PrintArgs() function, `args' became that argument: containing 1, code, ..., 2. After the code marker of PrintArgs()'s arguments, `args' was the parameter list that ran PrintArgs's arguments; i.e. the one containing only the number 9. Each function call temporarily replaced the existing args variable with its own argument list; the old args came back when each function exited.

Arguments within arguments get confusing very quickly. We'll suffer one final example at level 3 to hammer in our last point about how args behaves to the left and right of a code marker. Suppose we defined the following two functions:


    f :: {
       code
       
       g( print(args, " -- "), code, print(args) )
    }
   
    g :: { code, args("B") }
   

That is, f() runs g(), which in turn runs its own arguments. Now if we make the function call written below, we obtain the following output.


    > f("A")
   
    A -- B
   

Focus on the argument list in the function call to g() (in the line after f()'s code marker). The first half ran before g()'s code began, when args still had old value `A'. The second half of this argument list didn't run until g() called it with new arguments, at which point args was now `B'. What this example demonstrates is that args takes on a different meaning after, but not before, a code marker within a function call than it had in the code surrounding the function call.

Is there ever an earthly point to having functions running arguments that run their own arguments, etc.? Well, sometimes yes, and one good reason has to do with the `permissions' that different functions have to access different variables. A piece of code has access to other variables and functions along its own search path. This applies to function argument lists as well as the functions themselves. Thus, whereas function A has access to its own members, plus the members of its enclosing class or function, etc., an argument list of A(...) has access to variables defined in whichever function B() made that call, along with the members of the class or function enclosing B, etc. By calling one's arguments with specific, on-demand requests, a function can exchange information with the calling function as the need arises.

As we show in the example below, one possible use of the args code is to set optional parameters that are otherwise assigned a default value. We will have a prettier way of accomplishing the same thing by the end of the next section.


    lookup :: {
       word :: language :: string
       mode :: ubyte   | 1 = definition, 2 = thesaurus
       ...
       
       code
       
       word = args[1]   | get required params
       
       mode = 1   | set defaults
       language = "English"
       
       args(mode, language)
       
       ...
    }
   

We can run this script with minimal arguments, if we are satisfied with the defaults:


    lookup( "ulterior" )
   

or we can adjust one or several of the optional parameters after a code marker:


    lookup_mode :: ubyte
    in_str :: string
    print("Type '1' for definition; '2' for synonyms: ")
    in_str = input()
    read_string(in_str, lookup_mode)
   
    lookup( "munificent", code, args[1] = lookup_mode )
   

To make one final remark: we can replace any `code' marker flanked by commas or ends-of-lines with just a semicolon `;'. That latter shorthand was especially intended to be a less floral replacement for the `, code, ' sequence in function arguments. With that in mind, let's dress up the lookup() call above using a semicolon instead:


    lookup( "munificent"; args[1] = lookup_mode )
   

The moral of this section is that the coding block of a function's argument list may sound abstruse but it is not. In particular, its ability to set optional parameters (elaborated on in the next section) has proven truly useful in the author's hands. But the range of conversational possibilities between the function and the calling script is much broader, and greatly unexplored by the author.


Prev: Defining functions (properly)   Next: Code substitution


Last update: July 28, 2013

Get Yazoo scripting language at SourceForge.net. Fast, secure and Free Open Source software downloads