Data types
The Data Types table below summarizes the data types available for use in Synergy DBL. The “Valid in” columns indicates whether types can be used with traditional Synergy and Synergy .NET. See Data type descriptions for more details on each data type. See Where data types can be used for information on where (fields, parameters, return values) these types can be used.
The Data Types table includes the .NET data types for which we have created a shorthand type (e.g., “uint” for System.UInt32), those for which there is also support in traditional Synergy, and those for which we perform some special handling. However, you can use any data type in .NET’s System namespace when you compile with the Synergy .NET compiler. (This namespace is imported automatically when you use the Synergy .NET compiler.) For example, commonly used types including Char, DateTime, Guid, IntPtr, and UIntPtr. Char, IntPtr, and UIntPtr are included in the table below because of special alignment with Synergy .NET (see Char and IntPtr and UIntPtr). See also Understanding .NET data types. For complete details on .NET data types, see System Namespace in the Microsoft documentation. |
Valid in |
Description |
Default valuea |
||
---|---|---|---|---|
Traditional |
.NET |
|||
|
|
Alpha |
NA |
|
|
|
Alpha with initial value |
The initial value used to size the a |
|
|
|
Fixed-length 8-bit character sequence |
Spaces of specified size |
|
|
|
System.Boolean in .NET; maps to i4 in traditional |
false |
|
|
|
System.Byte in .NET (an unsigned 8-bit integer); maps to i1 in traditional (a signed 8-bit integer) |
0 |
|
char |
|
|
System.Char in .NET (a 16-bit numeric value); supports values for only one byte in traditional | 0 |
|
|
NA |
||
|
|
Decimal with initial value |
The initial value used to size the d |
|
|
|
Fixed-length decimal |
Array of character “0” (zero) of specified size |
|
|
|
Implied-decimal |
NA |
|
|
|
Fixed-length implied-decimal |
Array of character “0” (zero) of specified size |
|
|
|
0.0 in .NET; array of character “0” (zero) of size 28 in traditional |
||
|
System.Double in .NET; maps to d28.10 in traditional |
0.0 |
||
|
System.Single in .NET; maps to d28.10 in traditional |
0.0 |
||
|
|
Integer |
NA |
|
|
|
Integer with initial value |
The initial value used to size the i |
|
|
|
Signed 8-bit integer |
0 |
|
|
|
Signed 16-bit integer |
0 |
|
|
|
Signed 32-bit integer |
0 |
|
|
|
Signed 64-bit integer |
0 |
|
|
|
System.Int32 in .NET; maps to i4 in traditional |
0 |
|
|
System.IntPtr |
0 |
||
|
|
System.Int64 in .NET; maps to i8 in traditional |
0 |
|
|
|
Whole number numeric |
NA |
|
|
|
Implied and whole number numeric |
NA |
|
|
Packed |
NA |
||
|
Packed |
Array of character “0” (zero) of specified size |
||
|
Implied-packed |
NA |
||
|
Implied-packed |
Array of character “0” (zero) of specified size and precision |
||
|
|
System.Sbyte in .NET; maps to i1 in traditional (a signed 8-bit integer) |
0 |
|
|
|
System.Int16 in .NET; maps to i2 in traditional |
0 |
|
|
|
System.String in .NET; Synergy DBL System.String in traditional |
^NULLc |
|
|
Generic type parameter |
|
||
|
System.UInt32 |
0 |
||
|
System.UIntPtr |
0 |
||
|
System.UInt64 |
0 |
||
|
System.UInt16 |
0 |
||
|
|
A calling convention. See ^VAL below. |
NA |
|
|
|
Method does not return a value |
NA |
|
|
|
System.Object in .NET; shorthand for Synergy DBL System.Object in traditional |
^NULLc |
|
|
|
A specific class type |
^NULLc |
|
|
A specific delegate |
^NULLc |
||
|
A specific interface |
^NULLc |
||
|
|
A specific boxed type |
Depends on data type |
|
|
|
A specific enumeration |
0 |
|
|
|
A specific structure type |
Individual fields are initialized based on their type |
|
|
|
Dynamic array of the specified type |
Depends on value type |
|
|
|
Dynamic array, where array can have up to 9 dimensions (for example, [#,#,#,#]) |
^NULLc |
|
D_ADDR |
|
|
A data type identifier for a routine address | 0 |
D_ADDRSIZE | The size of a native pointer | NA | ||
D_GRFA_TYPE | GRFA-required type and size | NA | ||
D_HANDLE |
|
|
A data type identifier for a memory handle | NA |
D_MAXINT | Maximum supported int size | NA | ||
D_NATINT | Size of native int in C | NA | ||
D_NATLNG | Size of native long in C | NA | ||
D_RFA_TYPE | RFA-required type and size | NA |
a. In traditional Synergy, fields in stack records and DATA statements, other than objects, have no default value.
b. Not recommended for use in traditional Synergy.
c. ^NULL represents an uninstantiated object handle and can be used wherever an object can be used.
Understanding .NET data types
With Synergy .NET, there are three basic types of data types: value types, descriptor types, and class types. All inherit from the .NET class System.Object. This means, for example, that you can use System.Object methods, such as ToString, with all Synergy .NET data types.
|
Value types are structures in the .NET System namespace (System.Int32, for example). They directly access data and are, therefore, the most efficient data types. For example, in Synergy .NET, int maps to the System.Int structure.
Descriptor types use a class that contains information on the data type and memory location of actual data. Consequently, descriptor types aren’t as efficient as value types, but they do have the following advantages:
- Only parameters defined as descriptor types can be optional. (See Where data types can be used.)
- Only descriptor types can be used as variable arguments (i.e., the extra arguments you get with VARARGS; this is not true of value types or class types).
- Descriptor types have more flexibility than other types when assigning one type to another or when passing a type as a parameter that’s defined as another type. See Where data types can be used.
In this classification, all other data types are class types. This includes System.Object itself, as well as @class, @interface, @delegate, @value_type, and any other class data type, such as System.String.
The table below shows how the Synergy .NET data types are classified:
Value types |
Descriptor types |
Class types |
---|---|---|
boolean byte char decimal double float int IntPtr long sbyte short structurea T uint UIntPtr ulong ushort ^VAL |
a a* asize d d. d* dsize dsize.precision i i* i1, i2, i4, i8b n n. structurea |
@*, System, System.Object @class @delegate @interface @value_type [#,#]value [#,#]@* [#,#]@class [#,#]@value enumeration T |
a. If the CLS modifier is included in the structure definition, it’s a value type; otherwise it’s a descriptor type.
b. When passed, i1, i2, i4, and i8 are descriptor types. Otherwise, Synergy .NET optimizes them by making them value types.
When resolving types. the compiler first looks for an exact case match. If an exact match is not found, type resolution becomes case insensitive. For example, if we have
fld1, @class1 fld2, @Class1
and both class1 and Class1 are defined, they will resolve to those names exactly. However, if there is only a class1 or a CLASS1, it will resolve to either of those names.
A nullable type represents all values of an underlying data type plus an additional null value. (For example, a nullable Boolean type can have a value of true, false, or null.) A nullable type maps to the System.Nullable structure, and its primary purpose is to enable you to set value types to ^NULL.
To declare a nullable type, specify a question mark (?) after the data type. For example,
Myfield, integer?
Only non-Synergy value types may be specified as nullable types. If nullable syntax is specified on a Synergy type (such as a, d, etc.), for example,
nafld, a20?
an “Invalid expression at or near ?” error (INVEXPR) is generated.
Since Nullable is a generic type, you can alternatively declare a nullable type as follows:
Myfield, Nullable<T>
The default value for an item whose type is nullable is ^NULL.
You can use a cast to convert from a nullable type to its “base” type, as in the example below:
intvar = (int)nullableintvar nullableintvar = ^null
IF (nullable) is true when the result is not ^NULL or 0, and IF (!nullable) is true when the result is ^NULL or 0.
Data type descriptions
An alpha value (a, a*, asize) is a consecutive sequence of characters that can be treated as a unit of information. Alpha data can include only printable ASCII characters, and alpha values are limited to 65,535 characters on 32-bit platforms running traditional Synergy.
- a defines an alpha parameter, return type, or method property.
- a* defines an alpha data field where the initial value of the field (which is required for a*) is used to determine the field’s size.
- asize defines an alpha data field, parameter, return type, or method property of the specified size. By default, asize values are filled with spaces.
See Where data types can be used for more information.
Alpha types are descriptor types and have the same functionality for both traditional Synergy and Synergy .NET.
See the Synergex YouTube video Alpha Data for more information about the alpha data type. |
The boolean data type represents a Boolean (true/false) value. The default boolean value is false.
With traditional Synergy, boolean maps to i4. A boolean value is evaluated as %TRUE if true, and as %FALSE if false.
With Synergy .NET, boolean is a value type and maps to the .NET System.Boolean structure.
See the Synergex YouTube video Boolean Data for more information about the boolean data type. |
With traditional Synergy, the byte data type represents an eight-bit signed integer and maps to i1. With Synergy .NET, byte represents an eight-bit unsigned integer and maps to the .NET System.Byte structure. The default for a byte value is 0.
If you are using byte as a signed integer in traditional Synergy, we recommend that you use sbyte instead.
With traditional Synergy, the char data type represents a C# char (a 16-bit numeric value, which maps to the .NET System.Char structure). Char enables a DBL program to reserve a field of size 2 and write records with chars in them, which can then be read by C# programs.
The d, d*, and dsize types represent decimal data, which are signed, whole numbers that consist of ASCII numeric characters. The d., dsize.precision, and decimal types represent implied decimal data, which are signed numbers that consist of a whole number part and a fractional precision.
- d and d. define a decimal or implied decimal parameter, return type, or method property. These types are descriptor types and have the same functionality for both traditional Synergy and Synergy .NET.
- d* defines a decimal data field where the initial value of the field (which is required for d*) is used to determine the field’s size. This is a descriptor type and has the same functionality for both traditional Synergy and Synergy .NET.
- dsize and dsize.precision define a decimal or implied decimal data field, parameter, return type, or method property of the specified size. These are descriptor types and have the same functionality for both traditional Synergy and Synergy .NET. The default value is an array of character “0” (zero) of the specified size.
- decimal defines an implied decimal data field, parameter, return type, or method property. With traditional Synergy, decimal maps to d28.10, and the default value is an array of character “0” (zero) of size d28. With Synergy .NET, decimal is a descriptor type, maps to the .NET System.Decimal structure, and has a default of 0.0.
See Where data types can be used for more information, and note the following:
- A negative sign (–) doesn’t take a data storage place (the sign is stored in the right-most digit with a “p” through “y”, corresponding to 0 through 9). And for implied-decimal data, the decimal point does not take a data storage place.
- Decimal data can have from 1 to 28 significant digits. For implied-decimal data, the maximum size of the whole number part is 28 significant digits, and the maximum size of the fractional precision is also 28 digits, for a maximum total of 56. (d56.28).
The f designation for the fixed-point data type in previous versions of Synergy DBL is still valid with traditional Synergy, where it is processed as implied-decimal. Fixed-point is not supported in Synergy .NET. |
See the Synergex YouTube videos Decimal Data and Implied-Decimal Data for more information about the decimal and implied-decimal data types. |
With Synergy .NET, double is a value type and maps to the .NET System.Double structure. The default value is 0.0.
Double is not recommended for use with traditional Synergy (where it maps to d28.10 and has a default of 0.0).
With Synergy .NET, float is a value type and maps to the .NET System.Single structure. The default is 0.0.
Float is not recommended for use with traditional Synergy (where it maps to d28.10 and has a default of 0.0).
An integer value is a byte-oriented, binary representation of a signed whole number. Depending on how and where it is specified, an integer can be a value type or a descriptor type.
- i defines an integer parameter, return type, or method property. This is a descriptor type and has the same functionality for both traditional Synergy and Synergy .NET.
- i* defines an integer data field where the initial value of the field (which is required for i*) is used to determine the field’s size. This is a descriptor type and has the same functionality for both traditional Synergy and Synergy .NET.
- i1, i2, i4, and i8 define one-, two-, four-, or eight-byte integers. The default value for these types is 0, and they accept the following range of values:
Type
Minimum value
Maximum value
i1
-128
127
i2
-32768
32767
i4
-2147483648
2147483647
i8
-9223372036854775808
9223372036854775807
These types have the same functionality for both traditional Synergy and Synergy .NET. In general, they are descriptor types, but Synergy .NET usually optimizes them by making them value types and mapping them to the .NET System.SByte, System.Short, System.Int32, and System.Int64 value types.
- int (or integer) maps to i4 with traditional Synergy. With Synergy .NET, it is a value type and maps to the .NET System.Int32 structure. The default is 0.
Note that these types are stored in native integer form, so data files that contain integer data (including ISAM files) are not portable between big-endian and little-endian machines. (To convert integer data between native and portable formats, use the %CNV_IP and %CNV_PI intrinsic functions.)
See the Synergex YouTube video Integer Data for more information about the integer data type. |
The .NET System.IntPtr and System.UIntPtr. Both are unsigned integers of native size, depending on platform (4 bytes on 32-bit and 8 bytes on 64-bit). Because .NET assemblies are platform agnostic, IntPtr and UIntPtr are aligned on an 8-byte boundary on both 32-bit and 64-bit systems, and they always take up 8 bytes, even though they use only four bytes for data on 32-bit systems. (Synergy .NET only)
With traditional Synergy, long maps to i8. With Synergy .NET, long is a value type and maps to System.Int64. The default value is 0.
The numeric types, n and n., define numeric parameters for subroutines, functions, and classes (with some exceptions; see Where data types can be used). Numeric parameters can be used to pass any of the numeric data types: decimal, packed, or integer (for n), and implied decimal or implied packed (for n.). The parameter is accessed as the type used in the calling routine. (You can use ^DATATYPE to find the data type passed.)
Numeric types are descriptor types and have the same functionality for both traditional Synergy and Synergy .NET.
Data in packed or implied-packed form (p, psize, p., or psize.precision) is stored as two digits per byte, plus an extra byte for the sign.
- p and psize define a packed field, parameter, or return type. For psize, the default value is an array of character “0” (zero) of the specified size.
- p. and psize.precision define an implied-packed field, parameter or return type.
Whenever a packed or implied-packed field is used in an expression, it is converted to a decimal or implied-decimal field, respectively. Because of these restrictions, the only way to pass an expression to a subroutine or function in packed form is to assign it to a packed field before using it. (See Assignment statements for information about assigning an expression to a packed field.)
Note that packed and implied-packed types cannot be used with classes and are not supported with the Synergy .NET compiler. See Where data types can be used for more information.
With traditional Synergy, sbyte maps to an i1. With Synergy .NET, the sbyte data type represents an eight-bit signed integer. It is a value type and maps to the .NET System.Sbyte structure. The default value is 0.
With traditional Synergy, short maps to an i2. With Synergy .NET, short is a value type and maps to System.Int16. The default value is 0.
With traditional Synergy, String (or System.String) maps to the Synergy DBL System.String class. With Synergy .NET, it maps to the .NET System.String class. In either case, the default value is ^NULL.
Note the following for traditional Synergy:
- String can be used in most places that alpha can be used. A string variable can be passed to a routine as an IN alpha argument but not an OUT alpha argument.
- String can be ranged and concatenated.
- On a 32-bit machine, if the string length is less than or equal to 65,535, storing a string to an alpha (avar=string), where the size of the alpha is smaller than the size of the string, operates the same as two alphas (for example, a10=a15) by silently truncating to the size of the destination variable.
- String can represent data that exceeds the maximum alpha size. However, once the string size exceeds 65,535 on a 32-bit machine, the string is no longer directly interchangeable with alpha data, and a “Map outside bounds of field or handle” error ($ERR_HSIZERR) is generated if you attempt to store or convert such a string to alpha. Therefore, if you use string data in the place of an alpha argument or variable, you must use ranging to ensure the resultant size does not exceed 65,535.
In Synergy .NET, String can also be concatenated with a number or an object.
See the Synergex YouTube video String Data for more information about the string data type. |
T represents a generic type parameter. Note that you can use any letter (not just T), with the restrictions that a generic type parameter cannot have the same name as a data type, and a generic type parameter name must be unique within the type parameters for the current declaration. See Generic types (.NET) for more information. (Synergy .NET only)
Uint is a value type and maps to the .NET System.UInt32 structure. The default value is 0. (Synergy .NET only)
Ulong is a value type and maps to the .NET System.UInt64 structure. The default value is 0. (Synergy .NET only)
Ushort is a value type and maps to the .NET System.UInt16 structure. The default value is 0. (Synergy .NET only)
^VAL is a calling convention rather than an actual data type. It is a qualifier to subroutine parameters and return values and specifies that the parameter or return value will be passed by value as a native integer.
With traditional Synergy, ^VAL values map to i4 for 32-bit systems and i8 for 64-bit systems. With Synergy .NET, ^VAL is a value type and maps to the .NET System.IntPtr structure. You can have an argument of type ^VAL that identifies a calling convention using a value up to the size of a 32-bit or 64-bit int in traditional Synergy or a System.Intptr value in Synergy.NET.
See ^VAL for more information.
VOID specifies that a method does not return a value.
@*, Object, or System.Object is the parent class of all objects, including all other data types. With traditional Synergy, this maps to the Synergy DBL System.Object class. With Synergy .NET, it maps to the .NET System.Object class, and because .NET assemblies are agnostic, it always takes 16 bytes and is aligned on a 16-byte boundary on both 32-bit and 64-bit systems.
The default value is ^NULL.
@class assigns an object reference to a field, parameter, return type, or method property. That class becomes the variable’s type and you can use the object to access the class’s functionality.
If the class identifier is not unique within all imported namespaces, you must qualify the identifier with its namespace. If it is unique, specifying the namespace is optional. For example, if class1 is unique, a declaration using just class1 will work:
my_object ,@class1
If class1 is not unique, the declaration might look like this:
my_object ,@UserNS.class1
You can use @class in a named or unnamed record with traditional Synergy or Synergy .NET. The default value is ^NULL.
@delegate assigns a delegate to a field, parameter, return type, or method property. The delegate becomes the variable’s type, and you can use the variable to access the delegate.
If the delegate identifier is not unique within all imported namespaces, you must qualify the identifier with its namespace. If it is unique, specifying the namespace is optional.
You can use @delegate in a named or unnamed record. The default value is ^NULL. (Synergy .NET only)
@interface assigns an interface to a field, parameter, return type, or method property. The interface becomes the variable’s type, and you can use the variable to access the interface. (Synergy .NET only)
If the interface identifier is not unique within imported namespaces, you must qualify the identifier with its namespace. If it is unique, specifying the namespace is optional. For example, if interface1 is unique a declaration using interface1 will work:
my_object ,@interface1
If interface1 is not unique, the declaration might look like this:
my_object ,@UserNS.interface1
You can use @interface in a named or unnamed record. The default value is ^NULL.
@type assigns a boxed type to a field, parameter, return value, or method property. In traditional Synergy, type may be an non-class data type. In Synergy .NET, type may be any value or descriptor type. (See the classification lists in Understanding .NET data types for how types are classified in Synergy .NET.)
You can use @type in a named or unnamed record with traditional Synergy or Synergy .NET. The default value depends on the data type.
The enumeration data type represents a set of related values. It has a name and one or more enumeration values associated with it. The compiler allows these values, or other integer values, to be assigned to a variable of the enumeration type. Enumeration values are represented by integer values, and with traditional Synergy, the enumeration type maps to i4. With Synergy .NET, it maps to System.Enum. The default value is 0.
It is possible to assign an integer value (including Boolean) to an enumeration variable by casting the integer value to the enumeration type. A cast is also required when an integer is expected but an enumeration is given, for example, in a conditional such as
if (intvar .eq. (int)color.red)
If the enumeration identifier is not unique within all imported namespaces, you must qualify the identifier with its namespace. If it is unique, specifying the namespace is optional.
The enumeration type supports bitwise comparisons and the == and != operations. See ENUM for details on declaring an enumeration.
A defined structure can be used as a data type for a field, parameter, return type, property, or local variable. The resulting construct is called a structfield. For example,
var1 ,mystruct
A structfield replaces group syntax to allow definition of a variable (or array) that is strongly prototyped when passed as a routine argument. It supersedes the syntax of using ^M with an alpha field. It is especially useful when used in conjunction with the System.Collections.ArrayList class to provide dynamic arrays of structures to replace using %MEM_PROC and ^M.
The following example shows how to declare a field as a structure and use that structure:
structure MyStructure first ,a10 last ,a10 ,"Initial" endstructure subroutine TestStructure stack record tt ,i4 person ,MyStructure ;Declare a field that has the size of the structure proc init person ;Clear first and set last to "Initial" person.first = "Joe" ;Assign a value to a field in the structure open(tt=0, i, "tt:") writes(tt, person) close(tt) xreturn endsubroutine
If the structure identifier is not unique within all imported namespaces, you must qualify the identifier with its namespace. If it is unique, specifying the namespace is optional.
Note that you can use structfields with traditional Synergy or Synergy .NET, where structfield is a value type (i.e., the CLS modifier is included in the structure definition). Wherever possible, if you’re using .NET value types, you should use CLS structures for efficiency reasons. CLS is ignored in traditional Synergy.
Individual fields are initialized based on their type. See Using a structure with a structfield for more information.
[#,#]type defines a dynamic array of the specified data type.
In traditional Synergy, [#,#]type maps to the Synergy System.Array class, and [#,#] can have 1 to 9 dimensions, inclusive ([#], [#,#], and so on, up to [#,#,#,#,#,#,#,#,#]). Type may be any non-class data type other than a, d, i, d28.10, or float. (For a, d, i, etc., use [#,#]@type.) For example,
my_str_array ,[#,#]struct1
In Synergy .NET, [#,#]type maps to the .NET System.Array class. Type may be any value or descriptor type. (See the classification lists in Understanding .NET data types for how types are classified in Synergy .NET.) The [#,#] is shorthand for System.Array.
The default value is ^NULL.
[#,#]@type defines a dynamic array in which the element is the specified boxed data type.
In traditional Synergy, [#,#]@type maps to the Synergy System.Array class, and [#,#] can have 1 to 9 dimensions, inclusive ([#], [#,#], and so on, up to [#,#,#,#,#,#,#,#,#]). Type may be any non-class data type.
In Synergy .NET, [#,#]@type maps to the .NET System.Array class. Type may be any value or descriptor type. (See the classification lists in Understanding .NET data types for how types are classified in Synergy .NET.) The [#,#] is shorthand for System.Array.
The default value is ^NULL.
[#,#]@class defines a dynamic array of the specified class. (The [#,#] is shorthand for System.Array.)
In traditional Synergy, [#,#]@class maps to the Synergy System.Array class and [#,#] can have 1 to 9 dimensions, inclusive ([#], [#,#], and so on, up to [#,#,#,#,#,#,#,#,#]). For example,
my_dyn_array ,[#,#,#]@system.string
In Synergy .NET, [#,#]@class maps to the .NET System.Array class.
The default value is ^NULL.
[#,#]@ defines a dynamic array of any type of object. (The [#,#] is shorthand for System.Array.)
In traditional Synergy, [#,#]@ maps to the Synergy System.Array class and [#,#] can have 1 to 9 dimensions, inclusive ([#], [#,#], and so on, up to [#,#,#,#,#,#,#,#,#]).
In Synergy .NET, [#,#]@ maps to the .NET System.Array class.
The default value is ^NULL.
The D_ADDR type is used for routine addresses for data fields, parameters, return types, and method properties. It’s a definition for a data type, rather than an actual data type. The default value is 0.
D_ADDR is i8 on 64-bit application targets and .NET AnyCPU and i4 on OpenVMS and 32-bit application targets.
D_ADDR is not supported for use with ^M or arguments to functions that take ^M. Handles for ^M should be defined using D_HANDLE.
D_ADDRSIZE is 8 on 64-bit application targets and .NET AnyCPU and 4 on OpenVMS and 32-bit application targets.
A built-in type that is available when declaring a GRFA variable. It is defined as an a10.
The D_HANDLE type is used to identify memory handles in traditional Synergy and Synergy .NET. It’s a definition for a data type, rather than an actual data type. It is an i4.
D_MAXINT is the maximum supported int size. D_MAXINT is always i8 on all current application targets.
D_NATINT is the platform-defined size of the int data type in the operating system C header files. D_NATINT is always i4.
D_NATLNG is the platform-defined size of the long data type in the operating system C header files. D_NATLNG is i8 on .NET and all 64-bit application targets except non-.NET Windows. On non-.NET Windows and all 32-bit application targets, it is i4.
D_RFA_TYPE is a built-in type that is available when declaring an RFA variable. It is defined as a6.