Compare the natural, compact syntax of a Yazoo function
y = f(x)
with the rigid formalism of an external function call:
error_code = call("f", x, y)
Wouldn't it be great if we could run our external functions using method number one. Well, for several reasons the author actually wants to keep the formal protocol of a call() command, but he almost always `wraps' a Yazoo function around it to avoid having to deal directly with the call(). There are other advantages to doing so as well: some tasks, such as memory allocation, type checking and typecasting, are much more easily done on the Yazoo side than in C. Here we'll write a wrapper for our imaginary f() function.
f :: {
x :: answer :: double
error_code :: ulong
code
(answer =@ *) @:: double | should always do this for return variable
| will explain later
if top(args) /= 1 or trap(x = args[1]) /= passed
print("Error in arguments to f\n")
return *
end if
error_code = call("f", x, answer)
if error_code == 0
return answer
else
print("Error ", error_code, " in function f\n")
return *
end if
}
It may look like a lot of huffing and puffing but we have accomplished some important things. First, note that if the function is called with the wrong arguments or in a way that the C routine does not like, an error message will be printed and the function will exit gracefully (though it won't return a value, possibly causing whatever called it to crash as it rightly should). It often involves more overhead to do the type-checking in C.
More importantly, the Yazoo function f() will accept numeric arguments of any type, signed or unsigned integer or floating point, whereas the C f() is probably expecting a double. This is reflected in the way the wrapper was written --- it explicitly defined the types all of the arguments to call(), including the return variable. The following example shows what happens when you don't.
call("f", 1, answer)
call("f", 1.5, answer)
In the first case the first argument to the C-encoded routine will be a signed long integer; in the second case it will be a double-precision floating point number. Due to this ambiguity the passing of constants to call() is to be discouraged. The user can, however, pass constants or variables of any type to the wrapper with abandon; Yazoo then performs the appropriate conversions before calling the C routine.
Depending on the function f(), the C program that performs the calculation may be rather involved. Oftentimes auxiliary memory is required, if for example f() is some heavy numerical thing. It is generally easier to do this memory allocation in Yazoo. If our function in the example above requires, say, two tables, one of whose entries needs indefinite storage, we might extend its wrapper with the following lines:
temp_1[3][5] :: ulong | add these above the 'code' statement
temp_2[4] :: string
...
error_code = call("f", x, temp_1, temp_2, answer)
Using Yazoo's linked list routines the C program will be able to treat the temp_2 variable as a dynamic array.
Finally, one can do some exotic things with a Yazoo function that are convenient for the top-level user. A favorite trick is used for functions that require many more parameters than the user will ever want to specify, although he would like to be able to modify them when he needs to. In Yazoo you can solve this problem by adding something like the following to the wrapper.
params :: { | add these above the 'code' statement
max_storage :: ulong
convergence :: step_size :: init_size :: double
file_to_write :: string }
...
| after the code statement, put:
params = { 10, 7.5, .001, 1e-15, "f_log" }
...
| replace the first if statement with the following:
if top(args) /= 1 or trap(x = args[1]) /= passed &
or trap((params<<args)()) /= 0
...
| replace the old 'call' command with:
error_code = call("f", x, temp_1, temp_2, params, answer)
Now we call our function as before: y = f(x), unless we want to, say, double the integration step size, in which case we do
y = f(x; step_size = that*2)
Although the wrapper resets the defaults with each function call, it subsequently invites the user to change these defaults. This sort of maneuver works because, in Yazoo, function arguments are themselves functions. Yazoo scripting is a topic that evidently requires somewhat more discussion than we have given so far, and that is the subject that will occupy most of the remainder of this document.
Last update: July 28, 2013