To finish off, we’ll write a pretty generic Cicada wrapper for myFunction() that can be adapted to wrap most other C functions. One advantage of a wrapper is that it will let us run myFunction by typing something like
yf = f(x, y0)
rather than
$myFunction(param, x, y, calcData)
The wrapper will also allocate data storage for our function, and prevent us from crashing the C code by passing in bad arguments. Don’t ask me what this function does.
myFunctionWrapper.cicada
f :: {
x :: string
y :: error_code :: int
calc_table :: [][] double
params :: {
dim1 :: dim2 :: int
doRecalc :: bool }
code
params = { 2, 5, true }
if trap(
{ x, y } = args | mandatory arguments
(params << args)() | optional arguments
) /= passed then (
print("usage: yf = f(xStr, y0 [; calcSize/doRecalc = ...])\n")
return )
calc_table[^params.dim1][^params.dim2]
error_code = $myFunction(params.doRecalc, x, y, calc_table)
if error_code == 0 then return y
else print("Error ", error_code, " in function f()\n")
}
Our wrapper function has two parts. The first part is everything before the code command, which defines the variables used by function f(). These include the input and output arguments, optional parameters, and even a calculation table used internally by the C routine (because it’s easier to pass storage into C than malloc/free it in C). The most important thing is that the wrapper explicitly defines the type of each variable passed into C, thus ensuring proper communication between the two languages. For example, when we write f("a", 5) the integer argument 5 will be converted to a double before handing it off to C, as required by myFunction().
The executable part of f() begins after the code marker. First f() reads its arguments (within a trap() statement so that we can fail gracefully with an error message if the function wasn’t called properly). Notice that there are two sorts of function argument: mandatory arguments (x and y) which are copied straightforwardly from a predefined args variable, and optional arguments stored in params with default values. The optional arguments be changed using a very peculiar Cicada trick: f() runs its own arguments, as a function, inside of its own params variable. Then it resizes calc_table, calls myFunction() and returns a result.
Load our wrapper by going to Cicada’s command prompt and typing:
> run("myFunctionWrapper")
Here are some examples of function calls we can make once we’ve loaded our wrapper:
result := f("a", 5)
print( f("z", 5.78; doRecalc = false) )
result := f("a", 5; dim1 = that*2, doRecalc = false)
Make sure to separate the mandatory and optional parameters using a semicolon, and separate all other arguments or commands using commas.
Most prepackaged Cicada functions are actually Cicada wrappers around C functions, and their source files ciclib.c and defs.c are a rich source of further examples.
Last update: November 12, 2025