skip to content

How do you perform bitwise operations in Kotlin, and how does this differ syntactically from Java?

level: juniorimportance: must knowfreq 55%

answer

  1. No &|^~<<>> symbols in Kotlin
  2. and/or/xor/shl/shr/ushr are infix functions
  3. inv() is a member, not infix (unary)
  4. Only on Int/Long (and unsigned types)
  5. Parenthesize when mixing with arithmetic/comparison

basics

~20 s

Kotlin has no &, |, ^, <<, >> symbols. Instead it uses named infix functions like and, or, xor, shl, shr on Int and Long. So you write a and b instead of a & b.

solid answer

~40 s

Kotlin deliberately omits Java's bitwise operator symbols (&, |, ^, ~, <<, >>, >>>). Instead, the standard library defines named infix functions on Int and Long: and, or, xor, inv (replaces ~), shl (signed left shift), shr (signed/arithmetic right shift), and ushr (unsigned/logical right shift). You call them infix-style: 0xF0 and 0x0F, 1 shl 4, x.inv(). inv() is a regular member function, not infix, because it is unary. These functions only exist on Int and Long (and the unsigned types) — Byte and Short get promoted to Int first. Because they are normal function calls, they bind with lower precedence than arithmetic, so parentheses are often needed: (a shl 2) + 1.

code

kotlin · 8 lines
kotlin
val a = 0b1100
val b = 0b1010
println(a and b) // 8  (0b1000)
println(a or b)  // 14 (0b1110)
println(a xor b) // 6  (0b0110)
println(a.inv()) // -13 (all bits flipped)
println(1 shl 4) // 16
println((a shl 1) + 1) // parentheses needed

go deeper

for a junior

Knows the symbol-to-word mapping and that you write 'a and b', 'a shl b'.

for a middle

Explains inv() is a member not infix, that only Int/Long support them, and the precedence pitfall.

for a senior

Discusses Byte conversion/masking and why parentheses matter when mixing with comparison/arithmetic.

for a principal

Reasons about API design tradeoffs of readable infix vs symbolic operators and impact on DSLs/readability.

## Why Kotlin uses words, not symbols Unlike Java/C, Kotlin does **not** reserve the punctuation operators `&`, `|`, `^`, `~`, `<<`, `>>`, `>>>` for bit manipulation. The language designers freed those tokens (some are used elsewhere or reserved), and instead expose bit operations as **named infix functions** in the standard library. An **infix function** is a function marked with the `infix` keyword that can be called without the dot and parentheses: `a shl b` is exactly `a.shl(b)`. ## The full mapping (Java symbol -> Kotlin function) - `a & b` -> `a and b` - `a | b` -> `a or b` - `a ^ b` -> `a xor b` - `~a` -> `a.inv()` (member function, NOT infix — it's unary) - `a << b` -> `a shl b` (shift left) - `a >> b` -> `a shr b` (arithmetic / signed right shift) - `a >>> b`-> `a ushr b` (logical / unsigned right shift) ## Where they live These functions are declared **only on `Int` and `Long`** (plus the unsigned `UInt`/`ULong`). There are no bitwise functions on `Byte`, `Short`, `Char`, `Float`, or `Double`. To bit-twiddle a `Byte` you first convert: `byteVal.toInt() and 0xFF`. ```kotlin val flags = 0b0000 val READ = 1 shl 0 // 1 val WRITE = 1 shl 1 // 2 val combined = READ or WRITE // 3 val hasWrite = combined and WRITE != 0 // careful with precedence! val cleared = combined and WRITE.inv() // remove WRITE bit ``` ## Precedence gotcha Because infix functions are ordinary calls, they have **lower precedence than arithmetic** and named-infix calls are left-associative with each other but bind looser than `+`, `*`, and comparison can be surprising. `combined and WRITE != 0` parses as `combined and (WRITE != 0)` which won't even compile (type mismatch); write `(combined and WRITE) != 0`. Always parenthesize when mixing shifts/masks with arithmetic or comparisons. ## Summary The semantics are identical to Java's bit operators on the same two's-complement 32/64-bit integers; only the surface syntax changed from symbols to readable words.

  • Why is inv() not an infix function?
    infix functions must take exactly one parameter besides the receiver. Bitwise NOT is unary (only a receiver, no argument), so it's a plain member function called with dot syntax: x.inv().
  • Can you use these on a Byte?
    No. Byte/Short have no bitwise functions. Convert with toInt() first, and usually mask with and 0xFF to avoid sign extension before operating.

Kotlin spells the bit operators out in words the way a calculator labels buttons 'AND'/'OR' instead of cryptic symbols.

saying these in an interview costs you the question

  • Claiming Kotlin supports & | ^ << >> operators like Java
  • Saying inv() is infix or writing 'a inv b'
  • Thinking Byte/Short have bitwise functions directly
  • Forgetting parentheses so 'mask and x != 0' fails to compile
  • Confusing shr and ushr

context