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.
Argument passed by reference (Synergy .NET only)
Argument passed by value (default except for global subroutines and functions whose parameters are not descriptor types) (Synergy .NET only)
Has a default value (see Default parameter values on .NET for rules on how to specify default values) (Synergy .NET only)
Read only (default for a method)
Read and write
Write only
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
Optional argument (default for a subroutine or function)
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:
Parameter name
Argument passed by descriptor (default). (traditional Synergy only)
Argument passed by reference (size is required and type cannot be n). (traditional Synergy only)
Argument passed by value (type must be integer)
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:
Real array
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.)
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. |
On OpenVMS and .NET, ^VAL arguments are passed in a native register of the same size as the type defined as D_NATINT. Your code should ensure that the values you pass fit in the native register. The register size is 32 on 32-bit platforms and 64 on 64-bit platforms. On .NET AnyCPU builds, the size is defined at runtime. |
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.
If you want to ensure that mismatched parameters are detected during compilation instead of at runtime, strong prototyping is required. See Prototyping for more information. |
In traditional Synergy, you can check whether an optional parameter was passed or not using ^PASSED. For example, public method ArgumentData, void required in value, a optional in hasBinaryData, boolean record encodeElement, boolean proc if(^passed(hasBinaryData)) then encodeElement = hasBinaryData else encodeElement = false |
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.
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:
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:
- Object handles are not allowed within the scope of a group. For example, the following is invalid:
public method mymethod, void group p1 h1 ,@myclass endgroup
- Object handles are not allowed in local records that are declared in REENTRANT routines or in common records or global data sections.
- In Synergy .NET, object handles are not allowed in real array elements.
- Object handles are REQUIRED by default and cannot be defined as OPTIONAL.
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.
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 revoir")
gives the following values:
arg1 |
3 |
arg2 |
“Hello” |
arg3 |
“au revoir” |
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.