Operators

Operators control the evaluation order of an expression and determine how the operands are combined to yield a final result. Each operator has a precedence level within the entire group of available operators. When an expression is evaluated, the operators act in order of their precedence.

An operator is either unary, binary, or ternary. (See the Precedence of Numeric Operators table for a list of operators and their type.) Unary operators act on a single operand and must appear on the left side of the expression. Binary operators act on two operands and are placed between the operands. Ternary operators take three operands.

Synergy DBL supports the following types of operations that occur outside of a class:

See Object operators for information about operators that can be used on a class.

Assignment operations

The assignment operation is equivalent to a single-line assignment statement, which is described in detail in Assignment statements. The equal sign is the most common assignment operator. Additional assignment operators are specific to numeric and bitwise operations. (See Additional numeric assignment operators and Additional integer assignment operators.)

Assignment operator

We refer to the equal sign as an assignment operator, because it assigns one operand to another. When you use the equal sign as an operator, the operand on the left must be a variable specification, and the operand on the right is treated as an expression and stored in the variable before the variable is used in the rest of the expression.

For example:

xcall sub(a=1, b=2, c="ABC")

is equivalent to the following:

a=1
b=2
c="ABC"
xcall sub(a, b, c)

In the following example, Y is set to 3 before it is added to X:

X + Y = 3

This characteristic enables you to create operations like the following:

if ((len=^size(arg)).eq.4)
Note

The assignment operator causes parts of an expression to be evaluated from right to left instead of left to right. See How assignment operators affect order of evaluation for more information.

For a description of the += addition assignment operator, see Concatenation and reduction.

Alpha operations

Conversion to and from System.String

Alpha operators allow both alpha and System.String operands in the same expression. However, prior to calling the appropriate operator, one will implicitly be converted to the other according to the following rules:

When an alpha operand is converted to System.String, it is not blank trimmed.

Concatenation and reduction

In alpha expressions, the addition (+), subtraction (–), and addition assignment (+=) operators perform string operations on alpha operands. The addition operator performs string concatenation, in which the operand on the right is appended to the operand on the left. The subtraction operator performs string reduction, in which the first occurrence of the operand on the right is removed from the operand on the left. If the operand on the right does not occur in the operand on the left, the result is the content of the operand on the left.

For example, the following expression yields a result of “abcdef”:

"abc" + "def"

The expression below yields a result of “xydefabc”:

"xyabcdefabc" - "abc"

The addition assignment operator modifies the value of a variable by concatenating the value currently stored in that variable with the value that follows the operator. For example,

record
    svar,   string
proc
    svar = "hello"
    svar += ", there!"      ;svar now contains "hello, there!"
end

A System.String can be concatenated with another string or, in Synergy .NET, with a number or an object. A non-string operand is converted into a string and appended to either the beginning or the end of the original string, depending on the order of the operands. (Objects are converted to strings by calling their ToString method.) The result of the expression is a string. For example,

main
proc
    data fred, string, "fred"
    data ivar, int, 4
    console.writeline(fred+ivar)        ;Results in "fred4"
end

Also see the Concat method in System.String.

String relational operators

String relational operations compare two operands. Either operand can be an alpha or System.String, and they are compared slightly differently than relational operators. The string relational operators available in Synergy DBL are as follows:

.EQS.

Equal to

.NES.

Not equal to

.GTS.

Greater than

.LTS.

Less than

.GES.

Greater than or equal to

.LES.

Less than or equal to

Alpha operands are compared according to the order of characters within the ASCII character set. The complete ASCII character set is listed in Appendix B: ASCII Character Set. If the alpha operands in an expression are the same size, the characters in corresponding character positions are compared. If the alpha operands differ in size, the shorter operand is logically extended with blanks on the right until it is the same size as the larger operand. For example, comparing “A” to “ABC” is logically equivalent to comparing “A ” to “ABC”.

The result of a string relational operation is either true or false. If the relation is true, the result is an integer value of 1. If the relation is false, the result is an integer value of 0.

Here are some examples:

Expression

Result

“ABCDEF” .eqs. “ABCDEF”

true

“ABCDEF” .eqs. “ABC”

false

The following expression yields a result of 5:

5 + 11 * ("AB" .eqs. "ABCD")

First, the statement that “AB” is equal to “ABCD” is evaluated to be false. Because false has a value of 0, the equation becomes 5 + 11 * 0, which equals 5.

If either operand is System.String, the corresponding System.String operator is called. Strings are equal if the length of both strings are equal as well as the contents of the both strings (according to the order of characters in the ASCII character set). A System.String object that is equal to ^NULL is less than a System.String object that is equal to “”.

Numeric operations

A numeric data hierarchy consists of the following data types, listed from highest to lowest:

If an operator has operands with different numeric types, the operand that is lower in the hierarchy is promoted to the data type of the higher one. For example, if an integer value and an implied-decimal value are operands in an expression, the integer is promoted to implied-decimal before the operation occurs, and the result is implied-decimal.

Note

For performance reasons, Synergy uses the platform’s native integer size for expression intermediates. On 32-bit platforms, if an i8 is explicitly used in an integer expression, an i8 intermediate is used. Otherwise, an integer expression not using i8s that results in a value exceeding the native i4 will wrap (not be promoted to an i8), and no error will be generated. If necessary, you can avoid this by using i8s instead but at a slight cost to integer performance. On 64-bit platforms, all integer expressions use native i8 intermediates.

Unary plus and minus operators

Unary plus and minus operators determine whether the numeric operand is positive (+) or negative (–). Synergy DBL ignores the unary plus operator, because it assumes unsigned values are positive. The unary minus operator changes the sign of the operand to its right. Successive minuses are combined algebraically. For example, two minuses become a plus, three minuses become one minus, and so forth.

The data type of the operation’s result is the data type of the operand.

Arithmetic operators

Arithmetic operators perform addition (+), subtraction (–), multiplication (*), division (/ and //), or (in Synergy .NET only) modulo (.mod.).

If neither operand contains an implied decimal point, the addition, subtraction, multiplication, and division operators perform standard, signed, whole number arithmetic. If either operand contains an implied decimal point, the intermediate will contain a fractional portion.

If you add a 1 to a d28 variable that contains all 9s, the number rolls over to zero.

If a division operation using “/” involves two whole numbers (decimal, integer, or packed), any fractional part of the result is truncated without rounding. For example, the following expression yields a result of 2, not 2.5 or 3:

5/2

Division by zero is illegal. If you try to divide by zero, you’ll get an “Attempt to divide by zero” error ($ERR_DIVIDE).

When you multiply or divide implied-decimal or implied-packed operands, the intermediate result of the operation is calculated to a fractional precision of 29 digits. It is then truncated or rounded to 28 digits. For example, the expression below yields a result of 0.6666666666666666666666666666 if truncation is the default or 0.6666666666666666666666666667 if rounding is the default:

2.0/3.0

Rounding is the default unless (in traditional Synergy) you set system option #11 or specify the TRUNCATE option in the SUBROUTINE statement, which indicates the start of the routine. See system option #11 and SUBROUTINE-ENDSUBROUTINE for more information. (Neither TRUNCATE nor system option #11 are supported in Synergy .NET.)

Using the “//” division operator always results in an intermediate result that contains a fractional portion.

In Synergy .NET, the .mod. operator performs a modulo operation, which finds the remainder of a division operation between two numbers. For example, 9 .mod. 2 is 1, because 9 / 2 is 4 with a remainder of 1.

Synergy DBL checks a numeric data field for invalid characters or length when that field is used in an arithmetic expression. If you use a decimal field that contains more than 28 digits, a packed field that contains more than 18 digits, an implied-decimal field that has a whole number part or fractional precision of more than 28 digits, or an implied-packed field that has a whole number part of more than 18 digits or a fractional precision of more than 10 digits, an “Arithmetic operand exceeds maximum size” ($ERR_BIGNUM) error is generated. If any nonnumeric characters other than a blank, a decimal point, or a sign (+ or –) are present in the operands, a “Bad digit encountered” error ($ERR_DIGIT) is generated.

Additional numeric assignment operators

Additional assignment operators for numeric operands include +=, –=, *=, and /=. These operators are more efficient than their equivalent expressions (shown in the following table).

Operation

Equivalent expression

A += B

A = A + B

A –= B

A = A – B

A *= B

A = A * B

A /= B

A = A / B

Rounding operators

There are two kinds of rounding operators: # and ##.

The # rounding operator is a binary operator that rounds the left operand (the value being rounded) by the number of digits specified by the right operand (the round value). For example, if the right operand has a value of 3, the rounding operation discards the rightmost three digits of the left operand and then adds 1 to the result if the leftmost discarded digit is greater than or equal to 5.

The following rules apply to rounding with the # operator:

Here are some examples:

Expression

Result

345671 # -1

compiler error

345671 # 0

345671

345678 # 3

346

345678 # 4

35

-345678 # 4

-35

345678 # 7

0

6789.456 # 1

compiler error

The ## rounding operator specifies true rounding (rounding without discarding any digits in the value to be rounded). It rounds the left operand (the value being rounded) by the number of digits specified by the right operand (the round value).

The following rules apply to rounding with the ## operator:

Here are some examples:

Expression

Result

123.456 ## -2

123.46

12345 ## 2

12300

345671 ## -1

345671.0

345671 ## 0

345671

345678 ## 3

346000

345678 ## 4

350000

-345678 ## 4

-350000

Relational operations

Relational operators

Relational operators (and their corresponding symbolic relational operators) compare two operands. The relational operators available in Synergy DBL are as follows:

.EQ. (or ==)

Equal to

.NE. (or !=)

Not equal to

.GT. (or >)

Greater than

.LT. (or <)

Less than

.GE. (or >=)

Greater than or equal to

.LE. (or <=)

Less than or equal to

When you use a relational operator, both operands must be either alpha or System.String, or both must be numeric. If only one of the operands is a string, the == (or !=, etc.) operator maps to .EQS. (or .NES., etc.); otherwise, it maps to .EQ. (or .NE., etc.). When using System.String operands, see Conversion to and from System.String.

Note

See the String operators table for a list of string operators and their equivalents.

The result of a relational operation is either true or false. If the relation is true, the result is an integer value of 1. If the relation is false, the result is an integer value of 0.

Numeric operands result in standard, signed arithmetic comparisons.

Alpha operands are compared according to the order of characters within the ASCII character set for the length of the shortest operand. See Appendix B: ASCII Character Set for the complete ASCII character set. If the alpha operands in an expression differ in size, only the number of characters in the shortest operand are compared.

Here are some examples:

Expression

Result

“ABCDEF” .eq. “ABC”

true

“ABCDEF” .eq. “ABD”

false

The following expression yields a result of 20:

17 + 3 * ("ABCD".eq."AB")

First, the statement that “ABCD” is equal to “AB” is evaluated to be true. Because true has a value of 1, the equation becomes 17 + 3 * 1, which equals 20.

Unsigned integer operators

Synergy DBL also supports the following unsigned integer operators:

.EQU.

Unsigned integer equal to

.NEU.

Unsigned integer not equal to

.GTU.

Unsigned integer greater than

.LTU.

Unsigned integer less than

.GEU.

Unsigned integer greater than or equal to

.LEU.

Unsigned integer less than or equal to

Boolean operations

Boolean operators

Boolean operators compare the truth value of operands. The Boolean operators are as follows:

.OR. (or ||)

OR

.XOR.

Exclusive OR

.AND. (or &&)

AND

.NOT. (or !)

NOT

The result of a Boolean operation is either true or false. If the operation is true, the result is an integer value of 1. If the operation is false, the result is an integer value of 0.

Boolean operators are evaluated from left to right. If the result of an .AND. or .OR. Boolean operation can be determined by the evaluation of the operand on the left, Synergy DBL won’t process the operand on the right. For example, in the following Boolean expression:

ndx .and. array(ndx)

the right operand, array(ndx), won’t be evaluated if the left operand, ndx, has a false truth value, because if ndx is false, the entire expression is false.

Bitwise operations

Bitwise operators

Bitwise operators perform Boolean operations on the bits within integer operands. (A bitwise operator can also be used within an enumeration.) If an operand is decimal, it is converted to integer before the operation. The bitwise operators are as follows:

.BOR. (or |)

Bitwise OR

.BXOR.

Bitwise exclusive OR

.BAND. (or &)

Bitwise AND

.BNAND.

Bitwise NOT AND

.BNOT. (or ~)

Bitwise NOT

<<

Bitwise left shift (Synergy .NET only)

>>

Bitwise right shift (Synergy .NET only)

If the size of the operands are not the same, the length of the smaller operand is logically extended to the length of the larger by adding null (0) high-order bytes. The size of the result is the size of the largest operand.

For example, in the bitwise expression:

i2var .band. i1var

where the variables are declared as follows:

i2var           i2,     256
i1var           i1,     -1

i1var is logically extended to an i2 field by adding a null high-order byte. The result of this operation is an i2 value of zero.

Bit shifting operators

Bitwise left shift and right shift operators give you more control over individual bits within integer types. When used in combination with other bitwise operators, the left and right shift operators (<< and >>) can access parts of fields that store flag data or combine and extract small pieces of data. They can be applied to Synergy decimal and integer types; decimal types are converted into integers before the shift is performed.

The << and >> operators shift, in bucket brigade fashion, the bits in the value on the left of the operator to either the left or the right by the number of bits specified by the value on the right of the operator. Here’s an example:

data x, i1,   3
data y, i1
y = x << 2

The binary value of x is 00000011. Shifting that left by two bits changes the binary value to 00001100, which is 12 decimal. In effect, x was multiplied by 22, or 4. If a 1 bit is shifted into the high bit of a signed field, the value will be negative; if a 0 is shifted into the high bit, the value will be positive. Any bits shifted out of the high end of the field will be lost, and 0 bits are shifted into the low end of the field.

If, on the other hand, x is shifted 1 bit to the right, as shown below:

y = x >> 1

the value becomes 1, so 00000011 becomes 00000001, in effect, dividing x by 21, or 2. Any bits shifted out of the low end of the field will be lost, and bits that match the sign bit (the high bit) will be shifted in from the high end, so a negative value remains negative and a positive value remains positive. This is called a sign extending right shift.

The following example shows a class that implements the right shift operator:

namespace ns1
class fred
    public method fred
        arg,   int
    proc
        val = arg
    end
    public property val, int
        method get
        endmethod
        method set
        endmethod
    endproperty
    public static method op_RightShift,    @fred
        arg1,   @fred
        arg2,   int
    proc
        arg1.val = arg1.val >> arg2   ;Right shifts the val property
        mreturn arg1
        end
    private myval,        int
endclass
endnamespace
proc
    data h, @fred,  new fred(125)
    h = h >> 3                        ;Calls the op_RightShift method
    console.writeline(h.val)
end

Additional integer assignment operators

Additional assignment operators for integer operands are |= and &=. Equivalent expressions are shown in the following table:

Operation

Equivalent expression

A |= B

A = (A .BOR. B)

A &= B

A = (A .BAND. B)

These additional assignment operators can make bit manipulation much clearer. For example, the following statement sets all of the bits within A that are also set within B:

A |= B

The statement below sets A to all bits set in A and B:

A &= B

Conditional operations

A conditional operation is the equivalent of an IF statement condensed into a single line of code. Full support is provided for the conditional, null coalescing, and null conditional operators when compiling with a -qrntcompat value of 110101 or greater. In runtime versions prior 11.1.1, some expressions involving temporary handles are restricted within ternary operations.

Conditional operator

The conditional operator (?:) defines a conditional expression that takes three operands: a condition, a result for true, and a result for false. This allows you to assign one value to the variable if the condition is true and another value if the condition is false.

It has the syntax

condition ? expression1 : expression2

where

condition

A Boolean expression that evaluates to true or false, Condition must be suitable for use in an IF statement.

expression1

The result of the operation if condition evaluates to true.

expression2

The result of the operation if condition evaluates to false,

Expression1 and expression2 can be any type, object, or value type, but they must be compatible types with one other or a TERNMSMCH error will occur.

For example,

main
proc
    begin
      data x, int, 5
      data y, int
      y = x > 4? 4: x          ;Results in 4 being assigned to y
      open(15,o,'tt:')
      writes(15,%string(y))
    end
endmain

Null coalescing operator

In Synergy .NET, the null coalescing operator (??) provides an easy, compact way to check if an operand is null, and if it is, to return an alternate value. The ?? operator returns the operand on the left if that operand is not null; otherwise it returns the operand on the right.

For example, for the expression

x = y ?? z

y is assigned to x unless y is null. If y is null, z is assigned to x. The types of x, y, and z must be objects or nullable.

You can also use the ?? operator to return a default value when a nullable type is assigned to a non-nullable type, as shown below:

data int_val,   int
data null_int,  int?
.
.
.
int_val = null_int ?? 10

If you attempt to assign a nullable value type to a non-nullable value type without using the null coalescing operator, a compile-time error will occur.

Null conditional operator

In Synergy .NET, the null conditional operator (?. in a path) enables you to conditionally test for null before performing a member-access operation, which allows you to handle a null check with a single line of code. The null conditional operator evaluates whether or not the object to its left is null. If it’s null, null is returned and the access chain is stopped, thereby avoiding a null reference exception. If it’s not null, the object to its right is fetched.

For example, the following expression is null if value is null:

value?.substring(0, length)

Here’s another example:

fred = parent?.a?.b?.c

The first ?. operator checks to see if parent is null. If not, it fetches what’s to the right; if so, it returns null and halts the access chain. The same process is repeated with a and b.

Note that using this feature affects inferred type determination. For example, if you have a class1 that has an integer field, intfld, and the following code (where cvar is of type class1):

data myfld = cvar?.intfld

the expression could return a null (if cvar was null) or it could return an int (the type of intfld), so the resulting inferred type would be nullable<int>.

However, if the statement were

data myfld = cvar.intfld

the resulting inferred type could only be int.

Null suppression operator

In Synergy .NET, the null suppression (or null forgiving) operator (!) can be appended to the end of a variable or expression to suppress nullability warnings involving that variable or expression. For example,

data cvar = cvar2 

will give a warning if the DATA statement is in a nullable region and cvar2 is “potentially null.” This can be suppressed by writing

data cvar = cvar2! 

which ignores the fact that cvar2 could be null. This can also be used to force a null value to be assigned to a non-null variable, such as

data cvar = ^null!

This operator can also be used in a path for method access (!.). For example, academy.student.Study() will give a null warning if the student variable is possibly null. You can suppress this warning by instead writing academy.student!.Study().

The null suppression operator has no effect when used outside of a nullable region. (See .NULLABLE for more information about nullable regions.)

Object operators

Object operators can be implemented within a class so they can be used on instances of the class.

To find out if the runtime class of an instance variable is from a particular class, use the .IS. operator. If the class provided is in the class hierarchy of the instantiated class of the instance variable, the .IS. operator returns true. If not, it returns ^NULL. For example,

MyOther myobj = new MyClass
if (myobj .is. MyClass)

Unary class operators

Synergy DBL supports the following unary operator methods for use on a class:

Unary operator methods

Unary operator method name

Unary operator

Example syntax

op_Increment

incr

incr obj

op_Decrement

decr

decr obj

op_UnaryNegation

-

-obj

op_UnaryPlus

+

+obj

op_LogicalNot

! (.not.)

!obj

op_True

truth condition

if (myclass)

A unary operator method is invoked with the appropriate syntax from the table above. For example, the following invokes the op_Increment() operator:

c1, @myclass
proc
    incr c1
end

A unary operator method must have one argument, and it must be the enclosing class type. The method must be declared as PUBLIC and STATIC, and it cannot return a VOID.

The unary operator method in the example below increments a myclass object:

public static method op_Increment, @myclass
    p1, @myclass
proc
    p1.m_value = p1.m_value + 1         ;m_value is an i4 field in myclass
    return p1
end

Binary class operators

Synergy DBL supports the following binary operator methods for use on a class:

Binary operator methods

Binary operator method name

Binary operator

Example syntax

op_Addition

+

obj + obj2

op_Subtraction

-

obj - obj2

op_Multiply

*

obj * obj2

op_Division

/

obj / obj2

op_ExclusiveOr

.xor.

obj .xor. obj2

op_BitwiseAnd

& (.band.)

obj & obj2

op_BitwiseOr

| (.bor.)

obj | obj2

op_BXOR .bxor. obj .bxor. obj2
op_BNAND .bnand. obj .bnand. obj2

op_LogicalAnd

&& (.and.)

if (obj && obj2)

op_LogicalOr

|| (.or.)

if (obj || obj2)

op_OnesComplement

~

if (~obj)

op_Equality

== (.eq.)

if (obj == obj2)

op_GreaterThan

> (.gt.)

if (obj > obj2)

op_LessThan

< (.lt.)

if (obj < obj2)

op_Inequality

!= (.ne.)

if (obj != obj2)

op_GreaterThanOrEqual

>= (.ge.)

if (obj >= obj2)

op_LessThanOrEqual

<= (.le.)

if (obj <= obj2)

op_LeftShift << obj = obj << obj2
op_RightShift >> obj = obj >> obj2

A binary operator method is invoked with the appropriate syntax from the table above.

A binary operator method must have two arguments, and at least one must be the enclosing class type. The method must be declared as PUBLIC and STATIC, and it cannot return a VOID. You can declare multiple binary operator methods of the same name within a class as long as their method signatures differ.

The binary operator method in the example below adds two myclass objects:

public static method op_Addition, @myclass
    p1, @myclass
    p2, @myclass
proc
    mreturn new myclass(p1.m_value+p2.m_value)
end

If either operand to a symbolic string relational operator is of type System.String, the operator will operate the same as its corresponding string relational operator:

String operators

Symbolic string relational operator

Equivalent Synergy string relational operator

==

.EQS.

!=

.NES.

>

.GTS.

<

.LTS.

>=

.GES.

<=

.LES.

If a string relational operator is used in an expression and one of the operands is System.String, the compiler assumes that both operands are System.String or can be converted to System.String, and the corresponding string operator is run. (See System.String for a list of string operators.) For == or .EQS. where an operand is System.String, the equality operator (op_Equality) is run, which ensures the lengths are equal and then performs a character-by-character comparison.

In Synergy .NET, or when compiling with the -qnoargnopt option in traditional Synergy, the USING statement also operates using string relational operators.

If the nonstring relational operator is used, the compiler assumes that both operands are of type alpha or can be implicitly converted to alpha.

To compare two boxed objects, you must first unbox them using a type cast.

When comparing two object references, the equality operator (.EQ. or ==) returns true only if the objects reference the exact same instance of an object. Otherwise, it returns false. If you declare the op_Equality operator for the class, the result of the op_Equality method is returned.

For example, assume ChildClass extends ParentClass.

var1    ,@ChildClass
var2    ,@ChildClass
var3    ,@ParentClass
var4    ,@ChildClass
var1 = new ChildClass()
var2 = var1
if (var2 .eq. var1)             ;True
if (var1 .eq. var2)             ;True
var3 = (ParentClass)var1
if (var3 .eq. var1)             ;True
if (var3 .eq. var2)             ;True
var4 = new ChildClass()
if (var4 .eq. var1)             ;False
if (var4 .eq. var2)             ;False
if (var4 .eq. var3)             ;False
clear var1
clear var2
if (var1 .eq. var2)             ;True
Note

In a Where expression (see Synergex.SynergyDE.Select.Where),

avar==avar

is equivalent to

avar.eqs.avar

The inequality operator (.NE. or !=) returns true if the objects do not reference the exact same instance of an object. Otherwise, it returns false. If you declare the op_Inequality operator for the class, the result of the op_Inequality method is returned.

The example below determines that myobj is uninstantiated (i.e., it has never been created with NEW):

if (myobj==^NULL)

Conversion operators

Synergy DBL also supports the op_Explicit conversion operator method, as shown below:

Conversion operator method name

Description

Example syntax

op_Explicit

Explicit type conversion

obj1 = (class1)obj2

op_Explicit must have one argument that designates the source of a conversion and a return type to denote the destination for the conversion. Either the argument type or the return type must be the enclosing class type, but they cannot be within the same class hierarchy.

The example below converts from i4 to myclass:

public static method op_Explicit, @myclass
    p1, i4
proc
    mreturn new myclass(p1);
end

The conversion operator method must be declared as PUBLIC and STATIC. You can declare multiple conversion operator methods within a class as long as their return types and argument types differ.

If you do an explicit conversion cast, the compiler performs the following steps in order.

For example, if the above op_Explicit() were defined, it would be legal to invoke the explicit conversion operator using this syntax:

c1, @myclass
x, i4, 5
proc
    c1 = (myclass)x
end

Op_Explicit has the following restrictions:

myclass.op_Explicit(5)

Resolving object operators

When resolving object operators, the compiler looks for the operators only in the direct classes involved in the operation; it does not search up the hierarchy for an appropriate operator that could work. For example, using the code below, the compiler will attempt to run the op_Explicit operation from class2. If class2 or class3 doesn’t have that operator, the compiler will not go up the class hierarchy looking for appropriate operators, but will instead generate an “Invalid cast operation” error, because the operator cannot resolve.

namespace ns1 
class class1 
public static method op_Explicit, @class3 
    parm1, @class1 
proc 
    .
    .
    . 
end 
endclass 
class class2 extends class1 
            parm1, @class2 
proc 
    .
    .
    . 
end 
endclass 
class class3 
endclass 

and

c2, @class2 
c3, @class3 
proc 
    c2 = new class2() 
    c3 = (class3)c2 

Order of evaluation

The following table lists the numeric operators available in Synergy DBL. It is organized by left-to-right precedence, with the operators that have the highest precedence at the top.

Precedence of Numeric Operators

Precedence

Operator

Type

Description

1

(class), ^A, ^D, ^F, ^I

Type conversion

Cast

2

array[dim]

 

Array access

function(arg)

 

Function or method call

3

+

Unary

Positive

Unary

Negative

4

# and ##

Binary

Rounding

5

<< and >>

Binary

Bitwise left shift and bitwise right shift (Synergy .NET only)

6

*

Binary

Multiplication

/

Binary

Division

//

Binary

Division implied

.mod.

Binary

Modulo (Synergy .NET only)

7

+

Binary

Addition

Binary

Subtraction

8

.EQ. or ==

Binary

Equal to

.NE. or !=

Binary

Not equal to

.GT. or >

Binary

Greater than

.LT. or <

Binary

Less than

.GE. or >=

Binary

Greater than or equal to

.LE. or <=

Binary

Less than or equal to

.EQS.

Binary

String alpha equal to

.NES.

Binary

String alpha not equal to

9

.GTS.

Binary

String alpha greater than

.LTS.

Binary

String alpha less than

.GES.

Binary

String alpha greater than or equal to

.LES.

Binary

String alpha less than or equal to

.EQU.

Binary

Unsigned integer equal to

.NEU.

Binary

Unsigned integer not equal to

.GTU.

Binary

Unsigned integer greater than

.LTU.

Binary

Unsigned integer less than

.GEU.

Binary

Unsigned integer greater than or equal to

.LEU.

Binary

Unsigned integer less than or equal to

10

.NOT. or !

Unary

Boolean NOT

.BNOT. or ~

Unary

Bitwise NOT

11

.AND. or &&

Binary

Boolean AND

.BAND. or &

Binary

Bitwise AND

.BNAND.

Binary

Bitwise NOT AND

12

.OR. or ||

Binary

Boolean OR

.XOR.

Binary

Boolean exclusive OR

.BOR. or |

Binary

Bitwise OR

.BXOR.

Binary

Bitwise exclusive OR

13

??

Binary

Null coalescing (Synergy .NET only)

14

?:

Ternary

Conditional

15

=

Binary

Assignment

+=

Binary

Assignment

–=

Binary

Assignment

*=

Binary

Assignment

/=

Binary

Assignment

|=

Binary

Assignment

&=

Binary

Assignment

When two or more operators of the same precedence (except for the assignment operator) are adjacent, they are evaluated from left to right. For example, A * B / C is evaluated by multiplying A by B and dividing the result by C.

How assignment operators affect order of evaluation

The presence of an assignment operator (=) causes an expression to be evaluated from right to left, which often mixes a left-to-right precedence order with a right-to-left precedence order and makes the order of evaluation quite confusing. In a right-to-left evaluation, the right side always has precedence over the left side, and the assignment operation occurs before the left side is evaluated.

For example, the expression

X + Y = 3 + Z

is evaluated as follows:

X + (Y = 3 + Z)

The expression 3 + Z is evaluated first, then Y is assigned to the result of 3 + Z, and finally X + Y is evaluated.

Likewise, the expression

X + Y = Z * 3 / I = 15

is evaluated as follows:

X + (Y = Z * 3 / (I = 15))

First it sets I to 15, then it divides 3 by I, multiplies the result of 3 / I by Z, sets Y to (Z * (3 / I)), and adds Y to X, in that order.

A balanced set of parentheses can clarify or alter the expression’s order of evaluation and enable you to make your expressions as complex as necessary. Use parentheses if you need to override the precedence order of the operations in your expression. Parentheses can also help make your code easier to read, because they clearly indicate which operations are evaluated first.

Here’s an example of when you’d want to override the normal precedence order. Let’s assume you want to use the following equation with variables that have the same data type:

If you wrote the expression as A + B / C – D, precedence rules would dictate that the division operation be performed first. Thus, the value would be calculated as if the function looked like this:

The only way to get the correct order of evaluation is to override the precedence rules with parentheses and write the expression as (A + B) / (C + D).

The expressions in the most deeply nested sets of parentheses are evaluated first. For example, in the following expression the G – H operation is evaluated first because it’s in the most deeply nested set of parentheses. D + E is evaluated next, followed by (F * (G – H)):

A + B * (C - (D + E) / (F * (G - H)) + I)

As another example, let’s assume the following variable values:

A = 10
B = 30
C = 5
D = 2

The following expressions will have the specified values:

Expression

Value

A + B / C * D

22

A + B / (C * D)

13

(A + B) / (C * D)

4

More examples of expressions

The examples in the table below assume that the data division contains the following information:

record 
    d5          ,d5     ,12345
    d53         ,d5.3   ,12.345
    a6          ,a6
    money       ,d6     ,127654
    y           ,d3     ,-326
    a           ,p1     ,4
    b           ,d2     ,10
    c           ,d2     ,20
    d           ,i1     ,5
    e           ,d5.3   ,12.300

Expression

Value

5/3

“ 1”

5//3

“1.6666”

5//3##–4

“1.6666”

(5//3)#0

runtime error

d5#0

“ 12345”

d5#1

“ 1235”

d5##1

“ 12350”

(5//3)##–4

“1.6667”

a+b– c

– 6

a*d

20

b/a

2

b//a

2.5

e/b

1.23

b+c/d*a

26

b+c/(d*a)

11

(b+c)/(d*a)

1

((b+c)/d)*a

24

money#a

13

y#2

-3

y#a

0

y#1

-33

a .eq. 4

1

a .ne. 4

0

‘abc’ == ‘def’

0

a .eq. 4 .and. b .eq. 10

1

a .and. b

1

a .and. 0

0