Writing and calling subroutines and functions

There are three categories of Synergy DBL routines: subroutines, functions, and ^VAL functions. This topic describes the differences between them, how to write them, and how to call them. (For information on the subroutines and functions that are supplied with Synergy DBL, see System-supplied subroutines and functions.)

Subroutines

A subroutine is a module of code called by a main routine, another subroutine, or a function. Synergy DBL has two kinds of subroutines: external and internal.

External subroutines

An external subroutine is a routine that is separate from the routine that calls it. An external subroutine can exist in the same source file as the calling routine or in a separate source file.

To create an external subroutine, use the SUBROUTINE statement. Use either the RETURN or XRETURN statement to return to the calling routine. We recommend using XRETURN because it overrides any nested internal subroutine calls. If there isn’t an explicit exit control statement, a STOP statement is implied at the end of a routine. See SUBROUTINE-ENDSUBROUTINE and XRETURN for more information.

External subroutine parameters are listed immediately after the SUBROUTINE statement using a format similar to that of field declarations. The subroutine defines the data type of each parameter, but the calling program defines the argument size. You cannot define initial values in parameter declarations. See Defining a parameter for more information.

The example below shows the external subroutine mult.

subroutine mult
    a_result    ,n                      ;Subroutine data division
    a_arg1      ,n
    a_arg2      ,n
proc
    a_result = a_arg1 * a_arg2          ;Set the return result
    xreturn                             ;Return to the calling routine
endsubroutine

External subroutines may be called using the XCALL statement. In traditional Synergy, unless the first parameter is an alpha, you can also call them as functions (i.e., in the form %subroutine), provided the first argument being passed contains the result of the operation and the subroutine is declared as an external function in your code. If the subroutine name is not preceded by “XCALL” (or by “%” if called as a function), keep in mind the Identifier resolution rules.

In the example below, the subroutine mult is called using the XCALL statement:

main
record
    retval      ,i4
proc
    xcall mult(retval, 3, 4)            ;Call mult subroutine as a subroutine
endmain

In the following example, the subroutine mult is called as a function. Note that we declare the subroutine as a function in order to call it as one.

main
record
    retval      ,i4
external function
    mult        ,i              ;Declare subroutine as function
proc
    retval = %mult(3, 4)        ;Call mult subroutine as a function
    stop
endmain

An external subroutine can be called from a C routine if that C routine was called from a Synergy DBL routine. It can be called directly on OpenVMS; on Windows and UNIX, it can be called using the C interface. See Synergy DBL C Interface for more information.

Internal subroutines

An internal subroutine is located in the same function or external subroutine in which it is called (hence the designation “internal”). It resides between the calling routine’s PROC statement and its corresponding END statement, and it begins with a label and ends with the RETURN statement. (See RETURN for more information.) No arguments are passed to an internal subroutine; it shares the calling routine’s data.

Internal subroutines are called using the CALL statement. Upon returning from the call, processing continues at the line that follows the CALL statement. (See CALL for more information.)

Note

When using TRY-CATCH-FINALLY or BEGIN-END blocks with local data declarations, calls to a prior scope are not allowed and generate a “Label label out of scope” error (LBLSCOPE). Only calls within the current scope or to a nested scope are allowed.

The example below shows the internal subroutine square.

main main
record work             ;Main routine's data division
    result      ,d5
    val         ,d3, 19
proc
    call square         ;Call to internal subroutine
    stop                ;Logical end of program
square,                 ;Start of internal subroutine square
    result = val * val
    return              ;End of subroutine, return to line after call
endmain

Functions

A function is a module of code that returns a value. It can be called by a main routine, another function, or a subroutine. A function name may be preceded by a percent sign (%). If it is not preceded by a “%”, keep in mind the Identifier resolution rules.

You can use a function in an expression any place a literal can appear. For example:

value=%function(arguments)

if (%function(arguments))

xcall subroutine(arg1, %function(arguments), arg3) 

A function can return a value of any data type directly to the calling program. However, in traditional Synergy, what appears to be a return value to the left of the equal sign is actually passed as an additional implied argument in front of the actual arguments. That is, Synergy DBL functions use the notation of a function but are not true functions. (See ^VAL functions for information on true functions.) For example, this call:

retval = %myRoutine(arg1, arg2)

is processed by the compiler as if it were this call:

xcall myRoutine(retval, arg1, arg2)

To create a function, use the FUNCTION statement, followed by the function’s data and procedure divisions. Use the FRETURN statement to return to the calling routine. If there isn’t an explicit exit control statement, a STOP statement is implied at the end of a routine. See FUNCTION-ENDFUNCTION and FRETURN for more information.

Note

Take care when naming your functions. A user-defined function with the same name as a system-supplied intrinsic function will replace the intrinsic function.

Function parameters are listed immediately after the FUNCTION statement using a format similar to that of field declarations. The function defines the data type of each parameter, but the calling program defines the argument size. You cannot define initial values in parameter declarations. See Defining a parameter for more information.

The example below shows the function mult.

function mult
    a_arg1      ,n
    a_arg2      ,n
record
    result      ,i4
proc
    result = a_arg1 * a_arg2
    freturn result
endfunction

To use a nonprototyped, nonlocal function in a program, you must declare it with the EXTERNAL FUNCTION statement and specify the data type of the return value. (See EXTERNAL FUNCTION-ENDEXTERNAL for more information.) In the example below, we call the function mult.

main
record
    retval      ,i4
external function               ;Declare function and specify return type
    mult        ,i
proc
    retval = %mult(3, 4)        ;Call mult function
endmain

Alternatively, you can run the Synergy Prototype utility (dblproto) with the -out=file option on your nonlocal functions, and then IMPORT the specified namespace into your program file. This enables you to use the functions without having to use the EXTERNAL FUNCTION statement.

A function can also be called as a subroutine by placing the return value as the first argument in the argument list. (This is possible because, as described above, Synergy DBL functions pass the return value as an argument.)

In the following example, the function mult is called as a subroutine.

main
record
    retval      ,i4
proc    xcall mult(retval, 3, 4)            ;Call mult function as a subroutine
endmain

When your routine needs to return only one value, it is more efficient to write it as a function than as a subroutine. As shown in the examples below, using a subroutine requires an additional line of code.

Subroutine:

xcall sroutine(retval, arg1)
if (retval) ...

Function:

if (%froutine(arg1)) ...

A function can be called from a C routine if that C routine was called from a Synergy DBL routine. It can be called directly on OpenVMS; on Windows and UNIX, it can be called using the C interface. See Synergy DBL C Interface for more information.

^VAL functions

In traditional Synergy, a ^VAL function is a “true” function. It returns an integer value that is the natural integer size of the machine. That is, for a 32-bit machine, it returns an i4; for a 64-bit machine, it returns an i8.

In Synergy .NET, a ^VAL function is a less optimized method that returns a System.IntPtr (D_ADDR) for compatibility with traditional. For best performance, use functions that return an int if the value you return fits in an int.

^VAL functions are similar to non-^VAL functions in that they start with a % and can be used in an expression anywhere a literal can occur. The primary difference between a ^VAL function and a non-^VAL function is in how the return value is handled. As described in Functions, in a non-^VAL function, the return value is really passed as an additional argument. In a ^VAL function, the return value is a “true” return value, not an argument. (The arguments passed in a ^VAL function correspond to the arguments as they are defined.)

Because the return value is not processed as an argument, a ^VAL function is more efficient than a regular function. For this reason, we recommend using ^VAL functions for all routines that return an integer. However, because the return value of a ^VAL function must be an integer that is the natural integer size of the machine, you have to use a regular function in cases where a different type of return value is required, such as alpha or even i8 on a 32-bit machine. Note that if the return value is not an integer, it is converted to one.

To create a ^VAL function, use the FUNCTION statement with the ^VAL qualifier, followed by the function’s data and procedure divisions. Use the FRETURN statement to return to the calling routine. If there isn’t an explicit exit control statement, a STOP statement is implied at the end of a routine. See FUNCTION-ENDFUNCTION and FRETURN for more information.

The example below shows the function mult written as a ^VAL function.

function mult, ^val
    a_arg1      ,n
    a_arg2      ,n
record
    result      ,i4
proc
    result = a_arg1 * a_arg2
    freturn result
endfunction

To use your ^VAL function in a traditional Synergy program, declare it with the EXTERNAL FUNCTION statement and specify ^VAL as the access type (unless you're compiling with the -X option). For example:

main
record
    retval      ,i4
external function
    mult        ,^val                   ;Specify ^VAL as the access type
proc
    retval = %mult(3, 4)                ;Call mult
endmain
Note

If you use the -X compiler option in traditional Synergy, you do not need to declare ^VAL functions with the EXTERNAL FUNCTION statement. See Compiling a traditional Synergy routine for more information.

On .NET and when using prototyping, EXTERNAL FUNCTION is ignored and is not recommended. -X is not available on .NET.

You can also call a ^VAL function as a subroutine. To do this, make the call with XCALL, and then call XSTAT to retrieve the ^VAL return value. This method is not as efficient because you must make two XCALLs. For example:

main
record
    retval      ,i4
proc
    xcall mult(3, 4)            ;Call ^VAL function mult as a subroutine
    xcall xstat(retval)         ;Retrieve the ^VAL return value
endmain

In traditional Synergy, the true return value can also be retrieved with a subroutine by returning the value with the XRETURN statement and then making a call to XSTAT to retrieve it. See XSTAT for more information and an example.