Operators
Once we know of the existence of variables, we can begin to operate with them. For that purpose, UnigineScript integrates operators. Operators are mostly made of signs that are not part of the alphabet but are available in all keyboards.
Numerical Operators#
Operation | Operator | Type | Description | Operand Types |
---|---|---|---|---|
Negation | - | unary | Returns a negated value of the operand (changes its sign to the opposite) | Scalars, vectors |
Increment | ++ | unary | Increments the operand by 1 (both prefix and postfix notations are supported) | Scalars |
Decrement | -- | unary | Decrements the operand by 1 (both prefix and postfix notations are supported) | Scalars |
Multiplication | * | binary | Multiplies one operand by another | Scalars, vectors |
Division | / | binary | Divides the first operand by the second operand | Scalars, vectors |
Modulo | % | binary | Returns a remainder after numerical division of the first operand by the second operand | int, long, float and double |
Addition | + | binary | Adds one operand to another | Scalars, vectors, string |
Subtraction | - | binary | Subtracts the second operand from the first operand | Scalars, vectors |
int a = 0, b = 0;
log.message("%d %d\n",++a,b++);
log.message("%d %d\n",++a,b++);
log.message("%d %d\n",a,b);
/* Output:
* 1 0
* 2 1
* 2 2
*/
Scalar Operands#
All numerical operators that take two operands of different types perform an automatic conversion of scalars. The result is always the biggest type of two.
Vector Operands#
Some of numerical operators are applicable to vector types. All vector types can be added to, subtracted from and multiplied by operands of the same type. However, when performing operations on different types of vector operands or vectors and scalars, only specific combinations of operands are possible, because vector types are mostly nonconvertible.
String Operators#
These operators take only string variables as operands.
Operation | Operator | Type | Description |
---|---|---|---|
Concatenation | + | binary | A string into which two operands are joined |
Strings can be concatenated not only with strings but with variables of any base type due to type casting.
float a = -3.9;
string str = "there can be a mixture";
str = str + " of integer (" + 56 + ") and floating point values (" + a + ")";
log.message("%s\n", str);
/* Output:
* there can be a mixture of integer (56) and floating point values (-3.9)
*/
Logical and Bitwise Operators#
These operators take only the following types of variables as operands:
Operation | Operator | Type | Description | Operand Types |
---|---|---|---|---|
Logical NOT | ! | unary | Negates a boolean expression | int, long |
Logical AND | && | binary | true, if both operands are true | int, long |
Logical OR | || | binary | true, if one or both operands are true | int, long |
Bitwise NOT (complement) | ~ | unary | Logical negation of each bit | int, long |
Bitwise AND | & | binary | Logical AND operation on each pair of corresponding bits | int, long |
Bitwise inclusive OR | | | binary | Logical OR operation on each pair of corresponding bits | int, long |
Bitwise exclusive OR | ^ | binary | Logical XOR operation on each pair of corresponding bits | int, long |
Shift left | << | binary | Shift bit pattern in the first operand to the left by the number of bits specified by the second operand | int, long ivec3 or ivec4 can also be the 1st operand |
Shift right | >> | binary | Shift bit pattern in the first operand to the right by the number of bits specified by the second operand | int, long ivec3 or ivec4 can also be the 1st operand |
All non-zero values are equal to true, however, if true should be returned as a result of some operation, it will be always 1. false is always 0.
Comparison Operators#
- Scalars of different types (int, long, float, double) can be freely comapared to each other, beacause of the automatic conversion of scalars.
- Vectors (vec3, vec4, dvec3, dvec4, ivec3, ivec4, mat4, quat) can only be compared with the same type.
Operation | Operator | Description | Operand Types |
---|---|---|---|
Equal to | == | Tests if both operands are equal | Scalars, vectors, string
int(0) can be compared to an empty string and v.v. |
Not equal to | != | Tests if both operands are not equal | Scalars, vectors, string
int(0) can be compared to an empty string and v.v. |
Less than | < | Tests if the first operand is less than the second operand | Scalars, string |
Greater | > | Tests if the first operand is greater than the second operand | Scalars, string |
Less than or equal to | <= | Tests if the first operand is less than the second operand or equal to it | Scalars, string |
Greater than or equal to | >= | Tests if the first operand is greater than the second operand or equal to it | Scalars, string |
If the statement is true, the operator returns 1, otherwise 0.
Assignment Operators#
Operation | Operator | Type | Description |
---|---|---|---|
Assignment | = | binary | Assign a value of the second operand to the first operand |
"If-then-else" replacement | ? : | ternary | Can be used for conditional assignment, if this whole expression is the second operand of the assignment |
The conditional operator ?: can be used as a shorthand for what would normally be single-line blocks of the "if-then-else" construction. If used appropriately, this operator can enhance readability of code. Its syntax is the following: test_expression1 ? then_expression : else_expression.
int a = 10;
int b;
b = (a > 9) ? 100 : 200; // ternary operator usage
// this expression is equal to the previous one
if(a > 9) {
b = 100;
} else {
b = 200;
}
log.message("b =" + (b))
/* Output:
* b = 200
*/
It is also possible to use the ?: operator in expressions. For example:
int a = 1;
int b = 2;
int c = 3;
int d = 4;
log.message("%s\n","test 1: " + (a == b) ? "a == b" : "a != b" + " final");
log.message("%s\n","test 2: " + ((c == d) ? "c == d" : "c != d") + " final");
log.message("%s\n","test 3: " + (a == b) ? "a == b and " + ((c == d) ? "c == d" : "c != d") : ("a != b and " + ((c == d) ? "c == d" : "c != d")));
test1: a != b final
test2: c != d final
test3: a != b and c != d
The assignment operator = can be combined with +, -, *, /, %, &, |, and ^. These combined operators (+=, -=, *=, /=, %=, &=, |=, and ^=) assign the result of the operation to the first operand (which must be a variable).
int a = 10;
int b, c;
a = b = c; // this won't work
a = b += c; // this won't work either
Access Operators#
Operation | Operator | Type | Description |
---|---|---|---|
Member access | . | binary | Access a member (the second operand) of the first operand. Can be used with: |
Scope resolution | :: |
|
Access an identifier outside its scope. For details, see scope resolution operator. |
Access by index | [] | binary | Access an element by it index. Can be used with classes, vectors, maps, vec3, vec4, mat4, and quat |
Type Testing Operator#
The type testing operator is serves to check the type of a given variable. The operator returns1 when:
- A given variable belongs to a specified type
- A given object is an instance of a specified class
- A given object is an instance of a class that derives from a specified class
The syntax of the operator is the following:
i is int
- One of the scalar types
- One of the vector types
- String
- User-defined class name
- External class name
For example, this operator can be used in an if-else statement:
class Foo { };
class Bar : Foo { };
void check(int v) {
string s = typeinfo(v);
// both the is operator and the is_int() function check if v is of the int type
if(v is int) log.message("%s is int\n",s);
if(is_int(v)) log.message("%s is int\n",s);
// check if v is of the float type
if(v is float) log.message("%s is float\n",s);
if(is_float(v)) log.message("%s is float\n",s);
// check if v is an instance of the Stream class or class derived from the Stream
if(v is Stream) log.message("%s is Stream\n",s);
// check if v is an instance of the File class
if(v is File) log.message("%s is File\n",s);
// check if v is an instance of the Foo or Bar class
if(v is Foo) log.message("%s is Foo\n",s);
// check if v is an instance of the Bar class
if(v is Bar) log.message("%s is Bar\n",s);
}
check(1);
check(1.0f);
check(new File());
check(new Foo());
check(new Bar());
int: 1 is int
int: 1 is int
float: 1 is int
float: 1 is int
File 000000000E9330E0 internal (5:0:0) is Stream
File 000000000E9330E0 internal (5:0:0) is File
Foo 000000000D06FCD0 (131072:0:0) is Foo
Bar 000000000D06FD00 (196608:0:0) is Foo
Bar 000000000D06FD00 (196608:0:0) is Bar
Operator Precedence#
If an expression contains several operators, they will be evaluated in the order shown below, from the top to the bottom.
Operation | Operator |
---|---|
Parentheses | () |
Access operators | [] . |
Unary operators | ! - + ++ -- |
Multiplicative operators | * / |
Additive operators, string concatenation | + - |
Bitwise shift | << >> |
Comparison operators | == != < > <= >= |
Bitwise NOT | ~ |
Bitwise AND | & |
Bitwise exclusive OR | ^ |
Bitwise OR | | |
Logical NOT | ! |
Logical AND | && |
Logical OR | || |
Assignment operators | = += -= *= /= %= &= |= ^= ?: |
Operator Overloading#
You can read about operator overloading here.