How arguments and parameters are handled

In Writing and calling subroutines and functions, we discussed briefly how arguments are treated in subroutines, functions, and ^VAL functions. This topic provides more detail about how arguments are passed and what happens when you make a routine call. For purposes of this discussion, we have divided routine arguments and parameters into three categories:

Actual arguments

Actual arguments are the arguments that you specify when you call a subroutine or function. For example, in the following calls, 1, “abcd”, var1, and 4 are actual arguments:

xcall instr(1, "abcd", var1)
retval = %string(4)

Formal parameters

Formal parameters are the parameters declared in a subroutine or function. For example, in this declaration, arg1 and arg2 are formal parameters:

subroutine sub
    arg1        ,a
    arg2        ,d

Activation arguments

(traditional Synergy only) Activation arguments are the arguments referenced internally by a Synergy routine at runtime.

In subroutines and ^VAL functions, the actual arguments become the activation arguments. For example, in this call, the actual arguments 1, “abcd”, and var1 become the activation arguments:

xcall instr(1, "abcd", var1)

In non‑^VAL functions, the return value is passed as an argument, becoming the first activation argument. For example, in this call, the return value retval and the actual argument 4 become the activation arguments:

retval = %string(4)

See Argument mapping during routine calls for more detail.

Argument mapping during routine calls

This section shows how calling subroutines and functions in the various supported ways affects how the actual and activation arguments and formal parameters are mapped. We also explain what goes wrong when you call a subroutine or function in an unsupported way.

Calling a subroutine as a subroutine

When calling a subroutine with the XCALL statement, the actual, formal, and activation mapping is straightforward. The first actual argument corresponds to the first activation argument, which corresponds to the first formal parameter. The second actual argument corresponds to the second activation argument, which corresponds to the second formal parameter, and so on.

For example, if this subroutine:

subroutine mysub
    arg1        ,n
    arg2        ,n
proc
    .
    .
    .
    xreturn
endsubroutine

is called with the XCALL statement like this:

xcall mysub(var1, var2)

the actual, activation, and formal mappings are like this:

Calling a function as a function

Because the return value of a Synergy function is not a “true” return value (see Functions), when you call a function by preceding it with a percent sign (%), the first actual argument corresponds to the second activation argument, which corresponds to the second formal parameter. The second actual argument corresponds to the third activation argument, which corresponds to the third formal parameter, and so on. The FRETURN statement corresponds to the first activation argument.

For example, if this function:

function myfunc
    arg1        ,n
    arg2        ,n
record
    retval      ,i4
proc
    .
    .
    .
    freturn retval
endfunction

is called like this:

result = %myfunc(var1, var2)

the actual, activation, and formal mappings are like this:

Calling a subroutine as a function

As discussed in External subroutines, you can call a subroutine as a function in traditional Synergy, provided that the first actual argument contains the results of the operation (and the subroutine is declared as a function in your code).

Important

You cannot call a subroutine as a function in Synergy .NET. You must always declare a function to call it as a function.

For example, if this subroutine:

subroutine mysub2
    retval      ,i4
    arg1        ,n
    arg2        ,n
proc
    .
    .
    .
    xreturn
endsubroutine

is called as a function like this:

result = %mysub2(var1, var2)

the actual, activation, and formal mappings are like this:

However, if the first actual argument is not the result of the operation, you should not call the subroutine as a function because the arguments will not map properly.

For example, if you were to call this subroutine:

subroutine mysub
    arg1        ,n
    arg2        ,n
proc
    .
    .
    .
    xreturn
endsubroutine

like this:

if (%mysub(var1, var2))

the actual, activation, and formal mappings are like this:

In a function call, the first activation argument is reserved for the return value of the function. As the mapping above shows, within the routine arg1 would be null and arg2 would use the value passed by var1. The value in var2 would be “stranded” because there is no corresponding formal parameter. Depending on the routine, you may be able to retrieve this value with ^ARG or ^ARGN, or you may receive an error.

Calling a function as a subroutine

If you pass the function return value as the first argument of the subroutine, you can call a function as a subroutine. (See Functions for more detail.)

For example, if this function:

function myfunc
    arg1        ,n
    arg2        ,n
record
    retval      ,i4
proc
    .
    .
    .
    freturn retval
endfunction

is called like this:

xcall myfunc(result, var1, var2)

In traditional Synergy, the arguments will map like this:

Failure to pass the return value as the first argument will cause argument mapping problems. For example:

Within the routine, the value of arg2 will be null. Upon returning from the routine, FRETURN returns the value in the first activation argument. Depending upon the routine and the type of data passed, you will more than likely receive some type of error.

In Synergy .NET,

xcall func(a,b,c)

is translated by the compiler to

a = %func(b,c)

Calling a ^VAL function as a function or a subroutine

Unlike regular functions, in ^VAL functions the return value is a “true” return value; it is not treated as an argument. (See ^VAL functions for details.)

For example, if this ^VAL function:

function myVfunc, ^val
    arg1        ,n
    arg2        ,n
record
    retval      ,i4
proc
    .
    .
    .
    freturn retval
endfunction

is called like this:

result = %myVfunc(var1, var2)

the arguments will map like this:

The argument mapping will look the same when calling a ^VAL function as a subroutine because the return value is retrieved with XSTAT rather than being treated as an argument.