Operator Expressions
Expressions are sequences of operators and operands. This page lists all operators and their canonical semantics. Operators in an expression are evaluated in an order according to operator precedence. Slang applications can declare custom implementations for most operators (see operator overload declarations).
Operands are inputs for an operator. Operands are either atomic expressions or subexpressions, possibly with parentheses to indicate subexpression grouping.
Slang operators come in the following forms:
- Postfix operators — operators that apply to a single operand. The position of the operator is after the operand. The associativity is left to right.
- Prefix operators — operators that apply to a single operand. The position of the operator is before the operand. The associativity is right to left.
- Binary operators — operators that apply to two operands. The position of the operator is between the
operands (infix operators). The associativity is:
- left to right for binary operators other than assignment.
- right to left for assignment operators, including compound assignment.
- Ternary conditional operator — special three-operand operator (see below). The associativity is from right to left.
- Other operators — Function call, generic application, subscript, member access, scope
Built-in Operators
Arithmetic Operators (scalar)
| Operator | Operator function | Description |
|---|---|---|
+ |
__prefix T operator + (T val) |
identity (unary plus) |
- |
__prefix T operator - (T val) |
arithmetic negation (unary minus) |
++ |
__prefix T operator ++ (inout T val) |
increment in place, return incremented value |
++ |
__postfix T operator ++ (inout T val) |
increment in place, return value before increment |
-- |
__prefix T operator -- (inout T val) |
decrement in place, return decremented value |
-- |
__postfix T operator -- (inout T val) |
decrement in place, return value before decrement |
* |
T operator * (T lhs, T rhs) |
multiplication |
/ |
T operator / (T lhs, T rhs) |
division |
% |
T operator % (T lhs, T rhs) |
remainder |
+ |
T operator + (T lhs, T rhs) |
addition |
- |
T operator - (T lhs, T rhs) |
subtraction |
The arithmetic operators are defined for IArithmetic types. This includes built-in integer and floating-point scalar types.
Description:
- The identity (unary plus) operator returns the
valas is. - The arithmetic negation (unary minus) operator returns the negated value of
val. See IArithmetic.neg for details. - The prefix increment operator increments
valby 1 in place and returns the incremented value. - The postfix increment operator increments
valby 1 and returns the value before increment. - The prefix decrement operator decrements
valby 1 in place and returns the decremented value. - The postfix decrement operator decrements
valby 1 in place and returns the value before decrement. - The addition operator adds
lhsandrhs. See IArithmetic.add. - The subtraction operator subtracts
rhsfromlhs. See IArithmetic.sub. - The multiplication operator multiplies
lhsandrhs. See IArithmetic.mul for details. - The division operator divides
lhsbyrhs. See IArithmetic.div for details. - The remainder operator returns the remainder of
lhsbyrhsdivision such thatrem = lhs - n * rhswherenis an integer andabs(rem)<abs(rhs). The sign of remainder matches the sign oflhs. That is,lhs % rhs == lhs - trunc(lhs / rhs) * rhs. See IArithmetic.mod for details.
Logical Operators (scalar)
| Operator | Operator function | Description |
|---|---|---|
! |
__prefix T operator ! (T val) |
logical NOT |
&& |
T operator && (T lhs, T rhs) |
logical AND |
\|\| |
T operator \|\| (T lhs, T rhs) |
logical OR |
~ |
__prefix T operator ~ (T val) |
bitwise NOT |
& |
T operator & (T lhs, T rhs) |
bitwise AND |
^ |
T operator ^ (T lhs, T rhs) |
bitwise XOR |
\| |
T operator \| (T lhs, T rhs) |
bitwise OR |
<< |
T operator << (T lhs, int amount) |
bitwise left shift |
>> |
T operator >> (T lhs, int amount) |
bitwise right shift |
The logical operators are defined for ILogical types. This includes built-in integer and Boolean scalar types.
Description:
- The logical NOT operator interprets
valas a Boolean value and returns the opposite Boolean value. See ILogical.not for details. - The logical AND operator interprets
lhsandrhsas Boolean values and returnstrueif both operands aretrue. Otherwise, it returnsfalse. See ILogical.and for details. - The logical OR operator interprets
lhsandrhsas Boolean values and returnstrueif either operand istrue. Otherwise, it returnsfalse. See ILogical.or for details. - The bitwise NOT operator flips all bits in
valand returns the value. That is, bit value 0 becomes 1, and bit value 1 becomes 0. See ILogical.bitNot for details. - The bitwise AND operator performs the logical AND operation between every corresponding bit in
lhsandrhsand returns the value. See ILogical.bitAnd for details. - The bitwise OR operator performs the logical OR operation between every corresponding bit in
lhsandrhsand returns the value. See ILogical.bitOr for details. - The bitwise XOR operator performs the logical XOR (exclusive or) operation between every corresponding
bit in
lhsandrhsand returns the value. See ILogical.bitXor for details. - The bitwise left shift operator shifts all bits in
lhsleft byamount. See ILogical.shl for details. - The bitwise right shift operator shifts all bits in
lhsright byamount. See ILogical.shr for details.
The && and || operators short-circuit when their operands are scalars: the right-hand operand is evaluated
only when it can affect the result. That is, in lhs && rhs, rhs is evaluated only when lhs is true. In
lhs || rhs, rhs is evaluated only when lhs is false. When the operands are vectors or matrices, &&
and || do not short-circuit and evaluate both operands element-wise. Short-circuiting can be disabled
globally with the -disable-short-circuit compiler option.
Comparison Operators (scalar)
| Operator | Operator function | Description |
|---|---|---|
< |
bool operator < (T lhs, T rhs) |
less-than comparison |
<= |
bool operator <= (T lhs, T rhs) |
less-than-or-equal-to comparison |
> |
bool operator > (T lhs, T rhs) |
greater-than comparison |
>= |
bool operator >= (T lhs, T rhs) |
greater-than-or-equal-to comparison |
== |
bool operator == (T lhs, T rhs) |
equal-to comparison |
!= |
bool operator != (T lhs, T rhs) |
not-equal-to comparison |
The comparison operators are defined for IComparable types. This includes built-in integer, Boolean, and floating-point scalar types.
Description:
- The less-than comparison operator returns
trueiflhsis less thanrhs. Otherwise, it returnsfalse. See IComparable.lessThan for details. - The less-than-or-equal-to comparison operator returns
trueiflhsis less than or equal torhs. Otherwise, it returnsfalse. See IComparable.lessThanOrEquals for details. - The greater-than comparison operator returns
trueiflhsis greater thanrhs. Otherwise, it returnsfalse. Implemented usingIComparable.lessThanwith arguments swapped. - The greater-than-or-equal-to comparison operator returns
trueiflhsis greater than or equal torhs. Otherwise, it returnsfalse. Implemented usingIComparable.lessThanOrEqualswith arguments swapped. - The equal-to comparison operator returns
trueiflhsis equal torhs. Otherwise, it returnsfalse. See IComparable.equals for details. - The not-equal-to comparison operator returns
trueiflhsis not equal torhs. Otherwise, it returnsfalse. Implemented usingIComparable.equalswith the comparison result negated (logical NOT).
Assignment Operators (scalar)
| Operator | Operator function | Description |
|---|---|---|
= |
T operator = (inout T lhs, T rhs) |
assignment (non-overloadable built-in type) |
+= |
T operator += (inout T lhs, T rhs) |
compound addition and assignment |
-= |
T operator -= (inout T lhs, T rhs) |
compound subtraction and assignment |
*= |
T operator *= (inout T lhs, T rhs) |
compound multiplication and assignment |
/= |
T operator /= (inout T lhs, T rhs) |
compound division and assignment |
%= |
T operator %= (inout T lhs, T rhs) |
compound remainder and assignment |
&= |
T operator &= (inout T lhs, T rhs) |
compound bitwise AND and assignment |
\|= |
T operator \|= (inout T lhs, T rhs) |
compound bitwise OR and assignment |
^= |
T operator ^= (inout T lhs, T rhs) |
compound bitwise XOR and assignment |
<<= |
T operator <<= (inout T lhs, int amount) |
compound bitwise left shift and assignment |
>>= |
T operator >>= (inout T lhs, int amount) |
compound bitwise right shift and assignment |
The assignment operator is a built-in definition available for all copyable types. The assignment operator is not overloadable. See Special Types for a discussion on non-copyable types.
The default compound assignment operators behave as if implemented with the following template:
__generic<L: ..., R: ...>
L operator COMPOUND_ASSIGN_OP (inout L left, R right)
{
left = left OP right;
return left;
}
where COMPOUND_ASSIGN_OP is the operator combined with assignment and OP is the operator without
assignment.
The compound assignment operator is defined for the same types as OP. For example, += is defined for
IArithmetic types.
📝 Remark: Unlike in C/C++, the assignment operators return an R-value.
Miscellaneous Operators (scalar)
| Operator | Operator function | Description |
|---|---|---|
* |
__prefix Ref<T, a, s> operator * (Ptr<T, a, s, L>) |
pointer dereference (experimental) |
& |
__prefix Ptr<T, Access::ReadWrite, AddressSpace::Device> operator & (__ref T v) |
address of (experimental) |
, |
T2 operator , (T1 lhs, T2 rhs) |
comma operator (Slang 2025 and earlier) |
Canonical semantics:
- The pointer dereference operator returns the pointed value (L-value). The operand type is a pointer.
Note that the layout parameter
Lis not captured by the returned reference. See also Ptr. - The address of operator returns a pointer to the operand. The operand must be addressable.
- The comma operator (Slang 2025 and earlier) returns the right-hand-side parameter. Starting from Slang 2026, the comma is no longer an operator.
⚠️ Warning: The pointer dereference and address of operators are currently experimental in Slang. The details are subject to change.
📝 Remark: Starting from Slang 2026, the comma (
,) is no longer an operator. It is used as a separator in call expressions, initializer expressions, tuple expressions, and various declarations.
Ternary Conditional Operator
| Operator | Operator function | Description |
|---|---|---|
?: |
T operator ?: (bool cond, T trueVal, T falseVal) |
Conditional selection |
Description:
The conditional operator ?: is used to select between two values based on the condition (cond). If the
condition is true, trueVal is returned. Otherwise, falseVal is returned.
The default ternary conditional operator is provided for all copyable types.
The ternary conditional operator is short-circuiting for a scalar condition.
⚠️ Warning: The ternary conditional operator is also defined for vector condition operands for legacy reasons. In this deprecated form, the condition vector length must match the
trueValandfalseValvector lengths, and for each element, the corresponding element of the condition selects the corresponding element of eithertrueValorfalseVal. However, this form is non-short-circuiting. Use select() instead to make the non-short-circuiting behavior explicit.
Call Expression
Grammar:
callable-expr'('[arg-expr(','arg-expr)* ]')'
A call expression consists of a base expression callable-expr and a list of argument expressions
arg-expr.
The base expression must be a function, a member function, an invocable object (a struct with the function call operator defined), or a constructible type. In case the base expression is an identifier expression that is overloaded with multiple declarations, overload resolution selects the most appropriate one.
If the callable expression is a function, a member function, or an invocable object, the value of the expression is the return value of the invocation.
If the callable expression is a type, then an object of that type is instantiated and the arguments are passed to the constructor. The value of the call expression is the instantiated object.
If the argument type does not match with the parameter type, it is implicitly converted to the target type. It is an error if the implicit conversion is not available.
If an argument is not supplied to a parameter that has a default value, the default value is used. It is an error to omit an argument for a parameter that does not have a default.
If the callable expression is an invocable object or an object member and the function declaration is not
static, then the object is passed as the argument to the implicit this parameter.
Subscript Expression
Grammar:
base-expr'['[arg-expr(','arg-expr)* ]']'
A subscript expression consists of a base expression and a list of argument expressions.
The base expression type must be an array, a vector, a matrix, or a struct with the subscript operator defined as a member.
For array, vector, and matrix types, the built-in subscript operator semantics are defined by
IArray (for R-value base expressions)
and IRWArray (for L-value base
expressions). The subscript operator has a single argument, which returns the element of an array or a vector,
or the row vector of a matrix. The returned value is an L-value if base-expr is an L-value. Otherwise, it
is an R-value.
For struct types, the subscript expression is translated to a call to the subscript member
operator. If the subscript expression is an assignment or assignment-like expression, the call is translated
to the set accessor call of the subscript declaration. Otherwise, the call is translated to the get
accessor call. The arguments are passed as is. In case there are multiple __subscript declarations,
overload resolution selects the most appropriate one.
Member Expression
Grammar:
namespace-identifier('.''::')member-identifier
type-expr('.''::')member-identifier
value-expr'.'member-identifier
pointer-value-expr('.''->')member-identifier
A member access expression selects a member of a namespace, a type, or a value expression.
For namespace base expressions, member-identifier is an identifier within the namespace. For type
expressions, member-identifier is a member identifier.
For value expressions, member-identifier is a member of the value, such as a component, field, member
function, or a property. For scalars, vectors, matrices, and tuples, the member-identifier may also be a
sequence of components, resulting in a swizzle expression.
For pointer-typed and pointer-like values, members can be selected using either the . or -> operator. When
the . operator is used, the pointer is implicitly dereferenced as necessary. The arrow operator ->
selects a member through a pointer with an explicit dereference.
Member expressions are discussed in more detail in Member Expression.
⚠️ Warning: The arrow operator
->is currently experimental in Slang. The details are subject to change.
Cast Expression
Grammar:
'('type-expr')'base-expr
A cast expression converts a value (base-expr) to the desired type (type-expr). This is also known
as an explicit type conversion. See Expression Type Conversions for details.
Operators with Vector and Matrix Operands
For vector and matrix unary operators, the scalar operator is applied per element.
For binary operators with vector/vector and matrix/matrix operands, the vector and matrix dimensions must match and the scalar operator is applied per element.
For binary operators with vector/scalar and matrix/scalar mixed operands, the operator is applied on every vector or matrix element with the scalar operator.
The matrix/matrix and matrix/vector multiplication are special, and they follow the matrix multiplication rules. See Vector and Matrix Types for details.
📝 Remark: The short-circuiting behavior of operators
&&,||, and?:differs between scalar and vector/matrix operands. See sections Logical Operators (scalar) and Ternary Conditional Operator for details.
Non-Overloadable Operators
Parenthesized Expression
An expression wrapped in parentheses () is a parenthesized expression. It evaluates to the same value as
the wrapped expression. Parenthesized expressions can be used to control the evaluation order of
subexpressions.
Generic Specialization
Grammar:
gen-expr'<'[gen-arg-expr(','gen-arg-expr)* ]'>'
gen-arg-expr=type-exprvalue-expr
A generic type or an invocable (e.g., function) can be explicitly specialized by supplying the arguments to the generic parameters. When the arguments are not supplied, they are inferred as required. For details, see Parameter Binding in Generics.
Disambiguation between Generic Specialization and Less-Than Operator
Generic specialization is context-sensitive. When token < is encountered in an expression and the
left-hand-side operand is:
- known to be generic, then
<is considered to begin generic specialization. - known to be non-generic, then
<is considered as the less-than operator. - undetermined, then parsing as generic arguments is attempted. If parsing succeeds,
<...>is interpreted as generic specialization. Otherwise, the initial<is interpreted as the less-than operator. Parsing is considered successful if<...>can be parsed as generic specialization and it is followed by one of::,.,(,),[,],:,,,?,;,==,!=,>,>>, or the end-of-file marker.