Expression operators
Expression operators are used to compute values, for example,
with +
or -
. They are not to be
confused with stream operators, used to connect streams into a data flow
graph. The SPL operator table looks more or less like C, Java™, or Python:
Operator | Arity | Description |
---|---|---|
(e) | 1 | Parentheses for overriding operator precedence |
e(...) | N | Function call |
e[...] | N | Map lookup, or subscript or slice into string / blob / list |
e.id | 1 | Tuple attribute access |
(t)e | 1 | Type cast |
++ , -- , ! , - , ~ |
1 | Increment, decrement, prefix logical / arithmetic / bitwise negation |
* , / , % |
2 | Multiplication, division, remainder |
+ , - |
2 | Addition, subtraction |
<< , >> |
2 | Bitwise left-shift, right-shift |
< , <= , > , >= , != , == |
2 | Comparison (value semantics) |
& |
2 | Bitwise and |
^ |
2 | Bitwise xor |
| |
2 | Bitwise or |
&& |
2 | Logical and (short-circuit) |
|| |
2 | Logical or (short-circuit) |
?: |
2 | Ternary conditional |
in |
2 | Membership in list / map / set |
= , += , -= , *= ... |
2 | Assignment (value semantics) |
?? |
2 | isPresent (identity semantics) |
! |
1 | postfix unwrap (identity semantics) |
?: |
2 | unwrapOrElse (identity semantics) |
In this table, precedence goes from high (at the top) to low (at the bottom). Literals, such as strings, maps, tuples, lists, have higher precedence than the highest-precedence operator. The middle column of the table indicates arity (the number of operands). All the binary operators (arity 2) are left-associative.
An expression
of the form (t)e
is treated as a cast if the left
side t
is a literal type or a simple or qualified
name. Examples of a cast include (list<int32>)[]
, (complex32)[2,3]
, (x)-y
,
and (a.b::c.d)e.f
. Examples of expressions that are
not casts even though they look similar include (f())e
and (x
.+ y)e
.
Besides the simple assignment operator (=
),
the following operators first perform a regular binary operation,
and then an assignment: +=
, -=
, *=
, /=
, %=
, <<=
, >>=
, &=
, ^=
,
and |=
.
SPL uniformly uses value semantics. Hence, even in the case of composite values, assignments always copy the contents, and comparisons always compare the contents, never the location, of a value.
The right-shift operator (>>
)
behaves differently for signed and unsigned integers. For signed integers,
it fills with the sign bit, whereas for unsigned integers, it fills
with zero. Use casts if you want to override this behavior.
The
equality comparison operators ==
and !=
work
on all SPL types, including complex and containers. The ordered comparison
operators <
, >
, <=
,
and >=
work on all ordered types. That includes most numeric
types (all except complex numbers), enumerations, blobs, time stamps
(where the ordering ignores the machine identifier), and strings (where
the ordering is lexicographical by logical character). Using <
, >
, <=
,
or >=
on complex numbers, containers, tuples, or Booleans
is a compile-time error.
SPL uses identity semantics to write code that is agnostic on whether it is dealing
with optional types. You can use three operators to access the value of optional types. Use the
isPresent (??
) operator to check if a variable or attribute is non-null. The
isPresent operator returns true
if the optional variable or attribute is non-null
and false
if the variable or attribute is null
. Use the
unwrap operator (!
) to access the value of an optional data type that is non-null.
Use the unwrapOrElse (?:
) operator to get either the data value of an optional type
if the value is not null
, or a default value if the value of the optional
type is null
.