Where do infix function calls sit in Kotlin's operator precedence, and how does that affect an expression like `1 + 2 shl 3` or `a == b and c`?
answer
- Infix < arithmetic/range, but > comparison/equality/&&/||
- `1 + 2 shl 3` = `(1 + 2) shl 3`
- `a == b and c` = `a == (b and c)`
- Opposite of C: `and`/`or` bind tighter than `==`
- Left-associative; parenthesize when mixing
basics
~10 sInfix calls have lower precedence than arithmetic operators (+, -, *) but higher than comparisons, equality, and the logical &&/||. So arithmetic binds first, then infix, then comparisons.
solid answer
~40 sNamed infix functions share one precedence level that sits **below** the named-operator arithmetic (`*`, `/`, `%`, `+`, `-`, range `..`) and **above** comparison (`<`, `>`), equality (`==`, `!=`), and the conjunction/disjunction (`&&`, `||`). So `1 + 2 shl 3` parses as `(1 + 2) shl 3` because `+` binds tighter than the infix `shl`. And `a == b and c` parses as `a == (b and c)` because infix `and` binds tighter than `==`. This is a frequent gotcha because `shl/shr/and/or/xor` are plain infix functions, not bitwise operators with C-style precedence — in C, `&` is *lower* than `==`, the opposite of Kotlin. Infix calls are also **left-associative** and don't mix with arithmetic operators without parentheses. When in doubt, add explicit parentheses.
code
kotlin · 8 linesval x = 1 + 2 shl 3 // 24 -> (1+2) shl 3
val y = 1 shl 2 + 3 // 32 -> 1 shl (2+3)
val flags = 0b1010
val mask = 0b0010
// Gotcha: this is `result == (flags and mask)`
val result = 0b0010
val ok = result == flags and mask // true: flags and mask = 2 == 2go deeper
Knows infix calls have a precedence and that parentheses make grouping explicit when unsure.
Places infix below arithmetic/range and above comparison/equality/logical, and predicts (1+2) shl 3.
Explains the C-vs-Kotlin bit-op precedence reversal and why it causes real bugs in masks/flags.
Advises team conventions (mandatory parens around mixed infix expressions) and weighs infix readability against precedence surprises.
## Where infix sits Kotlin has a fixed operator-precedence table. From **highest** to **lowest**, the relevant slice is: - Postfix: `++`, `--`, `.`, `?.` - Prefix: `-`, `+`, `!` - Multiplicative: `*`, `/`, `%` - Additive: `+`, `-` - Range: `..`, `..<` - **Infix function** (named infix calls) ← all infix functions live here - Elvis: `?:` - Named checks: `in`, `!in`, `is`, `!is` - Comparison: `<`, `>`, `<=`, `>=` - Equality: `==`, `!=` - Conjunction: `&&` - Disjunction: `||` So **infix is below arithmetic and range, but above `?:`, comparison, equality, and the logical operators.** ## Worked examples ```kotlin 1 + 2 shl 3 // (1 + 2) shl 3 = 3 shl 3 = 24, because + binds tighter than shl 1 shl 2 + 3 // 1 shl (2 + 3) = 1 shl 5 = 32, same reason a == b and c // a == (b and c) — infix `and` binds tighter than == ``` `shl`, `shr`, `ushr`, `and`, `or`, `xor`, `inv` are **ordinary infix functions on `Int`/`Long`**, NOT special bitwise operators. This is the #1 surprise for developers coming from C/Java where `&` has *lower* precedence than `==`. In Kotlin it is the reverse. ## Associativity and mixing - All infix calls are **left-associative**: `a foo b foo c` = `(a foo b) foo c`. - You **cannot** chain an infix call with another binary operator without making the grouping explicit; the precedence table resolves it deterministically, but readers often misread it. ## Why `to`/`until`/`downTo` read naturally Because infix sits just below arithmetic and range, expressions like `0 until list.size`, `n downTo 1`, `i to j` group exactly the way you'd read them aloud — the operands are simple values or already-computed sub-expressions, so there's rarely ambiguity. Trouble only appears when you mix infix with `==`/`&&` (config flags, bit masks). ## Practical rule When combining an infix call with `==`, `&&`, `||`, `?:`, or other infix functions, **add parentheses**. It costs nothing and removes the precedence trap entirely.
- How does Kotlin's bit-op precedence differ from C/Java?In C, `&`/`|`/`^` have lower precedence than `==`, so `a == b & c` means `(a == b) & c`. In Kotlin, `and`/`or`/`xor` are infix functions that bind tighter than `==`, so `a == b and c` means `a == (b and c)`.
- Are infix calls left- or right-associative?Left-associative: `a foo b foo c` evaluates as `(a foo b) foo c`.
saying these in an interview costs you the question
- Assuming bitwise infix functions follow C precedence
- Saying infix binds tighter than `*`/`+`
- Claiming infix is right-associative
- Believing `==` binds tighter than `and`
- Not reaching for parentheses when mixing infix with logical/equality operators