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:

Table 1. Expression operators used in SPL
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.