Defining a parameter

Parameters can be declared for subroutines, functions, methods, and delegates. A parameter definition has the following format:

{attribute[(value_list)]}

[param_mod] param_def [dimension]type[size][, default_value]

Parameter definition components

attribute

(optional) An attribute that inherits from System.Attribute with an attribute target of All or Field. For more information see Attributes (.NET). (Synergy .NET or xfServer/xfServerPlus only)

value_list

(optional) The values for the specified attribute. For more information see Attributes (.NET). (Synergy .NET or xfServer/xfServerPlus only)

param_mod

(optional) One or more of the following parameter modifiers. See the Mutually exclusive modifiers table. The default for subroutines and functions is OPTIONAL and unspecified and for methods is REQUIRED and IN.

BYREF

Argument passed by reference (Synergy .NET only)

BYVAL

Argument passed by value (default except for global subroutines and functions whose parameters are not descriptor types) (Synergy .NET only)

DEFAULT

Has a default value (see Default parameter values on .NET for rules on how to specify default values) (Synergy .NET only)

IN

Read only (default for a method)

INOUT

Read and write

OUT

Write only

MISMATCH

Allow an inappropriate ^ARG function to access the parameter value, allow a type variables to be passed to n parameters (and vice versa for a subroutine or function), and allow d type variables to be passed to a parameters

OPT[IONAL]

Optional argument (default for a subroutine or function)

REQ[UIRED]

Required argument (default for a method, object, or dynamic array parameter)

param_def

The identifier used to reference the parameter. Param_def has one of the following formats:

name

Parameter name

^DESCR(name)

Argument passed by descriptor (default). (traditional Synergy only)

^REF(name)

Argument passed by reference (size is required and type cannot be n). (traditional Synergy only)

^VAL(name)

Argument passed by value (type must be integer)

group_def

Group definition (see GROUP‑ENDGROUP for syntax)

Parameter names adhere to the Synergy DBL naming conventions for identifiers. (See Identifiers.)

dimension

(optional) One or more array dimensions for the parameter type, designated in one of the following ways:

[*] (or [*,*], etc.)

Real array

[#] (or [#,#], etc.)

Dynamic array

(*)

Pseudo array (If the ‑qnet, ‑qcheck, or ‑qstrict compiler option is specified, or in Synergy .NET, only arrays can be passed to arguments marked with (*). If none of these options are specified, (*) is ignored.)

type

One of the following data types. (For more information on these types see the Data Types table; there are detailed descriptions of each type following the table.) You can also use any System.xxx type for type.

a

boolean

byte

d, d.

D_ADDR

decimal

double (Synergy .NET only)

float (Synergy .NET only)

i

int

long

n, n.

p, p. (traditional Synergy only)

sbyte

short

string

ushort (Synergy .NET only)

uint (Synergy .NET only)

ulong (Synergy .NET only)

@*

@class

@interface (Synergy .NET only)

@delegate (Synergy .NET only)

enumeration

structure

T (Synergy .NET only)

[#,#]value

[#,#]@value

[#,#]@class

[#,#]@*

size

The length of the parameter. Size is required only when ^REF is used.

default_value

(optional) The value the parameter will assume if not explicitly passed. The DEFAULT modifier must be specified. (Synergy .NET only)

Discussion

Traditional Synergy enables you to pass arguments to subroutines and functions in three ways: by descriptor (^DESCR), by reference (^REF), and by value as a native integer (^VAL). Arguments to Synergy DBL routines are normally passed by descriptor, which is the default. ^REF and ^VAL arguments are used primarily when passing arguments to non–Synergy DBL routines, but they may also be used with Synergy DBL routines. Note that ^REF is designed for use with OpenVMS system calls that require it and should not generally be used to pass arguments to Synergy DBL routines.

With traditional Synergy, the primary difference between these three ways of passing arguments lies in how the value of the argument is treated if it is updated by the routine. When an argument is passed by descriptor (^DESCR), if the variable associated with the parameter in the receiving routine is modified, upon returning from the routine, the value of the argument in the calling routine is also updated. A ^REF argument is treated the same way. However, when an argument is passed as ^VAL, the value is changed only locally, not in the calling routine.

In Synergy .NET, you can use BYREF, BYVAL, and ^VAL to pass Synergy type arguments to subroutines and functions. ^VAL passes a native integer by value. BYVAL passes a copy of the variable (by value) to the routine. BYREF, which is used only for objects (descriptor types and class types), passes a pointer to the object, so that if the called routine modifies the value, it’s modified for both the called routine and the calling routine. Note, however, that for descriptor types (a, d, i, n, etc.), unless BYREF is specified, the argument is passed by value but operates as if it were passed BYREF. In other words, the contents can be modified, but the length, address, and type can’t be changed. (See Passing different types of argument qualifiers for a comparison of how different types of argument qualifiers are passed in C#, traditional Synergy, and Synergy .NET.)

Note

Whenever you use ^REF or ^VAL to pass an argument to a Synergy DBL routine, the argument must be declared as ^REF or ^VAL in the routine.

   xcall mysub(^ref(arg1), ^val(var2)) 
   .
   .
   .
   subroutine mysub
     ^ref(arg1) ,i4 
     ^val(arg2) ,i

The following example illustrates the difference between ^REF and ^VAL arguments.

main
record 
   ttchn     ,i4    ,1
   var1      ,i4
   var2      ,i4
proc
   var1 = 10                    ;var1 and var2 are both 10 to start with
   var2 = 10
   xcall mysub(^ref(var1), ^val(var2))  ;pass var1 by reference
                                                ;pass var2 by value
   open(ttchn, o, "tt:")
   writes(ttchn, "^ref is " + %string(var1)   + " ^val is " + %string(var2))
   close ttchn
endmain
subroutine mysub
   ^ref(arg1)      ,i4          ;declare arg1 as ^ref in routine
   ^val(arg2)      ,i           ;declare arg2 as ^val in routine
proc
   arg1=arg1 + 20               ;we add 20 to both arg1 and arg2
   arg2=arg2 + 20
   xreturn
endsubroutine

The output from this program is

^ref is 30 ^val is 10

The value of the ^REF argument is updated in the calling routine, whereas the value of the ^VAL argument is updated only locally (i.e., within the subroutine).

A call to a routine declaring a REQUIRED (or REQ) modifier must provide a value for that argument. A call to a routine declaring an OPTIONAL (or OPT) argument can omit a value for that argument. ^VAL arguments are automatically marked required. Some data types cannot be declared as optional parameters; see the Where Data Types Can Be Used table for details.

For best performance in Synergy .NET, ensure IN and REQUIRED arguments are marked as such.

The MISMATCH modifier is allowed on an n, n., a, or d parameter type and enables the program to pass an alpha type as an argument to a numeric type without a prototype mismatch error. For subroutines and functions, MISMATCH is also allowed on an a parameter type, which enables the program to pass a decimal or an implied‑decimal argument to an alpha parameter.

Because of differences between traditional Synergy and Synergy .NET, be careful when using MISMATCH on an n parameter. MISMATCH n should only be used for routines that either pass the parameter as an argument to another routine marked MISMATCH n or when you explicitly use ^DATATYPE and cast with ^A of the argument. Otherwise, you may get unexpected results. In traditional Synergy, an alpha parameter passed to a MISMATCH n is typed decimal, whereas in Synergy .NET, the alpha parameter passed remains an alpha type, causing subtle behavioral differences. If you do not explicitly use ^DATATYPE and ^A and want to pass an alpha to a routine n argument, you can use ^D instead of making the routine MISMATCH n.

When using a MISMATCH a argument and expecting a d parameter to be accessed as an alpha, use ^DATATYPE and cast with ^A of the argument.

It you want to pass a decimal variable to a routine with a parameter typed as an alpha and you don’t use ^DATATYPE to cast the decimal variable when writing to it, do not use MISMATCH a. Instead, convert the routine to use a numeric parameter and use MISMATCH n, with appropriate use of ^DATATYPE and ^A when used as an alpha.

Note

In traditional Synergy, local n parameters implicitly act like MISMATCH n parameters, while routines resolved via prototype require that MISMATCH be explicitly stated.

The following parameter modifiers are mutually exclusive:

Mutually exclusive modifiers

Modifier

Cannot be used with

BYVAL/^VAL

BYREF/^DESCR, ^REF

BYVAL

INOUT (traditional Synergy)a, OUT

DEFAULT

INOUT, OUT, OPTIONAL, REQUIRED

IN

INOUT, OUT

OPTIONAL

REQUIRED

a. INOUT is allowed with BYVAL in Synergy .NET. Using INOUT with BYVAL allows for compatibility with C# where all BYVAL parameters can be modified. (By default BYVAL parameters cannot be modified in Synergy.) In this case, INOUT does not allow the parameter to be returned, but simply allows the parameter’s value to be modified, essentially treating the parameter as a local variable.

If param_def is a group definition, the parameter can have subfields that are explicitly sized and typed. An example of a group parameter is shown below:

subroutine mysub
arg1                    ,a10
group arg2              ,a
    arg2_field1         ,d3
    arg2_field2         ,d4
endgroup
arg3                    ,a8

When defining object handles (@class), note the following restrictions:

public method mymethod, void
    group p1
        h1 ,@myclass
    endgroup

For a dimensioned parameter (in other words, an array), the number of dimensions is indicated by asterisks (for a real array) or pound signs (for a dynamic array) separated by commas and enclosed in square brackets. The number of dimensions defined in the argument must match that defined in the calling routine. The number of elements in each dimension is not specified in the routine argument; rather, it is defined in the calling routine.

The following example shows how to declare two‑dimensional fixed and dynamic arrays in a subroutine.

subroutine mysub
    parm1       ,[*,*]a        ; fixed alpha array
    parm2       ,[#,#]@myclass ; dynamic array of myclass objects

If you pass a dimensioned variable to a parameter that has not been defined as an array, the routine will be able to access only the first element of the array. Should this variable then be passed to a second routine where the parameter is defined as an array (with the correct number of dimensions), the second routine will be able to access the entire array.

Any numeric type (i, d, p, n, and so forth) can be passed to an n type.

Note

When strong prototyping is enabled for routines marked IN or for which no directional modifier is specified, and the type is n or i, the compiler converts numeric literals to integers for improved performance.

If a parameter is a structfield, with strong prototyping, only a structfield of the same structure type can be passed.

Unless ^REF is specified, size is ignored on parameters, as it is defined by the caller. However, you may want (or, in some cases, need) to include size if you plan to attribute code for use with xfServerPlus. See Using attributes to define Synergy methods.

Default parameter values on .NET

The DEFAULT modifier enables you to specify default values for parameters that aren't explicitly passed to a routine. Parameters with default values must be grouped at the end of the parameter definition list, and each must begin with the DEFAULT modifier. On functions and subroutines, you must specify the IN modifier for parameters marked DEFAULT.

For example,

public method sample,                   void
    required arg1,      int
    default arg2,       short,          10
    default arg3,       Boolean,        false

The following CLS types are supported for default parameters.

Supported CLS data types for default parameters

Type

Default value example

boolean

%TRUE / %FALSE

byte

129

sbyte

‑10

short

‑345

unsigned short

38023

int

‑23

unsigned int

2

long

834245

unsigned long

8738702

float

23.5 (floating‑point literals)

double

2345.534 (floating‑point literals)

char

“a” (single‑character strings)

object handle

^NULL (cannot be set to an instance of the class)

CLS structure

new structuretype() (clears the structure)

nullable type

^NULL or supported literal for the base type

enumeration

supported literal for the enumeration type

decimal

3429.3 (System.Decimal literals)

string

“abcde” (multi‑character strings)

Note that arrays, groups, and non‑CLS structures are not supported. Generic types are supported. No code, including constructors, can be executed for default parameter values, so for object types other than System.String, the only acceptable literal value is ^NULL. CLS structures other than numeric types, such as System.DateTime or user‑defined structures, can only be defaulted to their cleared value by specifying “NEW” followed by the parameterless constructor for the CLS structure type.

Descriptor types are only supported within a compilation unit. The supported descriptor types and their default value forms are as follows:

Supported descriptor data types for default parameters

Type

Default value example

a

“abcde” (alpha literal strings)

i1

3

i2

1000

i4

11022

i8

3346363

d

2

d.

2.5

A routine that has been declared to have default values for some or all of its parameters is called the same way you’d call a routine with optional arguments: omit the default parameters but use commas as placeholders between parameters.

The example below shows default parameters being declared on .NET:

public method meth1,            void
    default arg1,       int,            5               ;CLS numeric types
    default arg2,       a,              "Hello"         ;alpha descriptor
    default arg3,       string,         "Goodbye"       ;string
    default arg4,       strc,           new strc()      ;CLS structure
    default arg5,       @*,             ^NULL           ;object type
    default arg6,       d,              20              ;decimal descriptor
    default arg7,       st2<int>,       new st2<int>()  ;Generic CLS structure
    default arg8,       obj<float>,     ^NULL           ;Generic object type

Given the above declarations, the call

meth1(3,,"au revoire")

gives the following values:

arg1

3

arg2

“Hello”

arg3

“au revoire”

arg4

Cleared instance of strc

arg5

^NULL

arg6

20

arg7

Cleared instance of st2<int>

arg8

^NULL

Arg2 receives its default value because it is skipped in the parameter list in the call. Arg4 through arg6 receive their default values because they are omitted at the end of the list of specified argument values.