Expressions¶
Overview¶
Expressions are almost identical to those found in C or Java. The same operator precedence rules apply:
Expression(s) | Operator(s) |
---|---|
Accessors | . ?. () [] |
Unary | - ! ~ ++ -- (cast) |
Multiplicative | * / % |
Additive | + - |
Bitwise Shift | >> << |
Elvis | ?: |
Relational | < <= > >= |
Equality | == != |
Bitwise AND | & |
Bitwise XOR | ^ |
Bitwise OR | | |
Logical AND | && |
Logical OR | || |
Ternary | ? : |
Assignment | = += -= *= /= |= ^= &= >>= <<= |
Arithmetic Operators¶
The following arithmetic operators may be used with numeric primitives:
Name | Operator |
---|---|
Multiplication | x * y |
Division | x / y |
Modulus (remainder) | x % y |
Addition | x + y |
Subtraction | x - y |
Negation | -x |
Prefix Increment | ++x |
Prefix Decrement | --x |
Postfix Increment | x++ |
Postfix Decrement | x-- |
The Modulus operator is only available for integer types, it may not be used with floats or doubles.
The prefix/postfix operators work just like C and Java. If using the prefix operator the result of the expression is the new value. If using the postfix operator the result is the old value:
int x = 4 // x == 4
int y = ++x // x == 5, y == 5
int z = x++ // x == 6, z == 5
Bitwise Operators¶
The following bitwise operators may be used with integer primitives (byte, short, int, long):
Name | Operator |
---|---|
Or | x | y |
Xor | x ^ y |
And | x & y |
Left Shift | x << y |
Right Shift | x >> y |
Not | ~x |
Logical Operators¶
The following logical operators may be used with booleans:
Name | Operator |
---|---|
Or | x || y |
And | x && y |
Not | !x |
Both the Or and And operators are short circuiting. If the first term of Or evaluates to true, then the second term is not evaluated. If the first term of And evaluates to false, then the second term is not evaluated.
Comparison¶
The following operators are used for comparison:
Name | Operator |
---|---|
Equal | x == y |
Not Equal | x != y |
Greater Than | x > y |
Greater Than or Equal | x >= y |
Less Than | x < y |
Less Than or Equal | x <= y |
Non-numeric types may only use the equality (==
and !=
) operators.
Reference types compare identity (pointer address).
Assignment¶
The =
operator is used to assign the right hand side expression to the
left hand side. The left hand side must be assignable. Assignable
expressions are local variables, fields, and array indices.
The compound assignment operators += -= *= /= |= ^= &= >>= <<=
can be
used to combine an arithmetic or bitwise operator with assignment:
int x = 5 // x == 5
x += 3 // x == 8
Assigning to Properties¶
If the left hand side of an assignment expression is a component property then you must use the := assignment operator instead of =. This highlights the fact that assigning a new value to a property results in more than just the storage of the new value; it also has potential side effects that may not always be visible to the user.
Note that there are no compound property assignment operators; increment, decrement, etc must be spelled out explicitly in the expression.
// Property px
property int px
// Non-property field ix
int ix
void myfunc()
{
// Use := when lhs is a property
px := 3
// Use = when lhs is a non-property
ix = px
// No compound assignment operators
px := px + 1
}
Casting¶
Sedona uses a syntax just like C or Java to perform a cast. Casts are
required when the compiler cannot perform a static type check. For
example, if you need to assign an Obj to a Component, then you must use
a cast: c = (Component)obj
. This type of cast is for compile time
checking only, at runtime it is basically a no-op like C.
Casts are also used with numeric types to perform a type conversion. For
example to convert an int into a float: f = (float)i
. Note that unlike
C and Java, upcasts such as from an int to a long are not implicit - you
must be explicitly use a cast.
Safe Navigation¶
Sedona supports Groovy's safe navigation operator: x?.slot
. You can
use the safe nav operator to access fields or call methods. If the
target expression of a slot access is null, then the whole expression
short circuits to evaluate to null. If the field or method returns a
primitive then it short circuits to false/zero. Using the safe nav
operator is a convenient and more efficient way than manually checking
for null:
// hard way
DeviceNetwork net = null
if (point != null)
{
Device dev = point.getDevice()
if (dev != null) net = dev.getNetwork()
}
// easy way
DeviceNetwork net = point?.getDevice()?.getNetwork()
Elvis¶
Sedona supports Groovy's elvis operator: lhs ?: rhs
. If lhs
evaluates to null, then the whole expression evaluates to rhs. If lhs is
non-null, then the rhs is short circuited and the whole expression
evaluates to lhs. The elvis operator is a convenient and more efficient
way to write code where you might use the ternary operator:
// hard way
name != null ? name : "unknown"
// easy way
name ?: "unknown"
Ternary¶
Sedona supports the C/Java ternary operator: c ? t : f
. The boolean
expression c
is evaluated. If true then the ternary expression
evaluates to t
, otherwise it evaluates to f
:
bool x = true
Str msg = x ? "On" : "Off" // msg == "On"
x = false
msg = x ? "On" : "Off" // msg == "Off"
String Interpolation¶
Sedona supports string interpolation, which allows for concise string
formatting. String interpolation can be used with any method that has
one Str
parameter and returns an OutStream
. You may use the "+"
operator to concatenate multiple expressions to a string literal:
// using the + operator
int x = 77
Sys.out.print("x=" + x)
// is equivalent to this statement
Sys.out.print("x=").printInt(x)
The example above illustrates why interpolation is only used with
methods that take a Str
and return an OutStream
. The compiler
doesn't actually create a new string, rather it chains multiple print
calls.
Use of the "+" operator is allowed, but the preferred mechanism for
string formatting is to embed the expressions directly into the string
literal itself using the '$'
character. You can embed any arbitrary
expression into a string literal using the syntax "${expr}"
. If the
expression is a simple variable name or a variable name followed by a
dot field access, then you can omit the curly braces. Use the '\$'
escape sequence to print the dollar sign itself. Some examples:
// example from above
Sys.out.print("x=${x}")
// same but omitting the braces
Sys.out.print("x=$x")
// embedded expressions
Sys.out.print("x=0x${Sys.hexStr(x)}")
The following types are supported with string interpolation:
Type | Print Method |
---|---|
Str |
OutStream.print |
bool |
OutStream.printBool |
int |
OutStream.printInt |
long |
OutStream.printLong |
float |
OutStream.printFloat |
double |
OutStream.printDouble |