Precedence and associativity
Precedence and associativity define the order in which operators are applied. Operators with higher precedence are bound to their arguments (operands) first, while operators with the same precedence bind in the direction of their associativity.
For example, the expression 1+2*3
according to the precedence for addition and multiplication is equivalent to 1+(2*3)
, and 2^3^4
equals 2^(3^4)
since exponentiation is right-associative.
Operators
The following table lists the available operators in Q#, as well as their precedence and associativity. Additional modifiers and combinators are also listed, and bind tighter than any of these operators.
Description | Syntax | Operator | Associativity | Precedence |
---|---|---|---|---|
copy-and-update operator | w/ <- |
ternary | left | 1 |
range operator | .. |
infix | left | 2 |
conditional operator | ? \| |
ternary | right | 3 |
logical OR | or |
infix | left | 4 |
logical AND | and |
infix | left | 5 |
bitwise OR | \|\|\| |
infix | left | 6 |
bitwise XOR | ^^^ |
infix | left | 7 |
bitwise AND | &&& |
infix | left | 8 |
equality | == |
infix | left | 9 |
inequality | != |
infix | left | 9 |
less-than-or-equal | <= |
infix | left | 10 |
less-than | < |
infix | left | 11 |
greater-than-or-equal | >= |
infix | left | 11 |
greater-than | > |
infix | left | 11 |
right shift | >>> |
infix | left | 12 |
left shift | <<< |
infix | left | 12 |
addition or concatenation | + |
infix | left | 13 |
subtraction | - |
infix | left | 13 |
multiplication | * |
infix | left | 14 |
division | / |
infix | left | 14 |
modulus | % |
infix | left | 14 |
exponentiation | ^ |
infix | right | 15 |
bitwise NOT | ~~~ |
prefix | right | 16 |
logical NOT | not |
prefix | right | 16 |
negative | - |
prefix | right | 16 |
Copy-and-update expressions necessarily need to have the lowest precedence to ensure a consistent behavior of the corresponding evaluate-and-reassign statement. Similar considerations hold for the range operator to ensure a consistent behavior of the corresponding contextual expression.
Modifiers and combinators
Modifiers can be seen as special operators that can be applied to certain expressions only. They can be assigned an artificial precedence to capture their behavior.
For more information, see Expressions.
This artificial precedence is listed in the following table, along with how the precedence of operators and modifiers relates to how tightly item access combinators ([
,]
and ::
respectively) and call combinators ((
, )
) bind.
Description | Syntax | Operator | Associativity | Precedence |
---|---|---|---|---|
Call combinator | ( ) |
n/a | left | 17 |
Adjoint functor | Adjoint |
prefix | right | 18 |
Controlled functor | Controlled |
prefix | right | 18 |
Unwrap application | ! |
postfix | left | 19 |
Named item access | . |
n/a | left | 20 |
Array item access | [ ] |
n/a | left | 20 |
Function lambda | -> |
n/a | right | 21 |
Operation lambda | => |
n/a | right | 21 |
To illustrate the implications of the assigned precedences, suppose you have a unitary operation DoNothing
(as defined in Specialization declarations), a callable GetStatePrep
that returns a unitary operation, and an array algorithms
that contains items of type Algorithm
defined as follows
struct Algorithm {
Register : Qubit[],
Initialize : Transformation,
Apply : Transformation,
}
The following expressions, then, are all valid:
GetStatePrep()(arg)
Adjoint DoNothing()
Controlled Adjoint DoNothing(cs, ())
Controlled algorithms[0].Apply!(cs, _)
algorithms[0].Register![i]
Looking at the precedences defined in the table above, you can see that the parentheses around (Transformation(GetStatePrep()))
are necessary for the subsequent unwrap operator to be applied to the Transformation
value rather than the returned operation.
However, parentheses are not required in GetStatePrep()(arg)
; functions are applied left-to-right, so this expression is equivalent to (GetStatePrep())(arg)
.
Functor applications also don't require parentheses around them in order to invoke the corresponding specialization, nor do array or named item access expressions. Thus, the expression arr2D[i][j]
is perfectly valid, as is algorithms[0]::Register![i]
.