skip to content

What is the difference between Kotlin's &&/|| and the and/or infix functions on Boolean? When does short-circuit evaluation matter?

level: middleimportance: should knowfreq 55%

answer

  1. && / || short-circuit; and / or do not
  2. Left operand guards the right (null/bounds checks)
  3. and/or/xor are infix functions, always both sides
  4. No '^' for Boolean — use xor
  5. Condition must be Boolean, not Int

basics

~20 s

&& and || are short-circuit: they stop early once the result is known, so the right side may not run. and/or always evaluate both sides. Use && / || when the right side has a side effect or could crash if reached.

solid answer

~50 s

Kotlin's logical operators &&, ||, and ! work on Boolean. && and || are short-circuiting: a && b skips b if a is false, and a || b skips b if a is true — so the right operand can be a guard like (x != null && x.size > 0). The infix functions and(other) and or(other) (plus xor) are non-short-circuiting: both operands are always evaluated, useful when you want every side effect to run or when avoiding branch logic. ! is logical negation. Boolean is a real type (not an int), so you cannot write if (1) — the condition must be Boolean. Common pitfall: calling a function with side effects on the right of && and being surprised it didn't run because the left was false. xor returns true when operands differ; there is no '^' operator for Boolean, you use xor.

code

kotlin · 7 lines
kotlin
fun loud(tag: String): Boolean { println(tag); return false }

val a = loud("L") && loud("R")  // prints: L         (R skipped)
val b = loud("L") and loud("R") // prints: L then R  (both run)

val guarded = (name != null && name.isNotEmpty())
val differ  = true xor false      // true

go deeper

for a junior

Knows && and || short-circuit and ! negates; conditions must be Boolean.

for a middle

Distinguishes and/or (always both sides) from &&/|| and explains guard expressions.

for a senior

Reasons about side-effect ordering, picks and/or to force evaluation, and notes the same names are bitwise on Int.

for a principal

Discusses readability/maintainability trade-offs, De Morgan refactors, and avoiding hidden control flow via side-effecting operands.

## Boolean operators in Kotlin `Boolean` has exactly two values, `true` and `false`, and is its own type — **conditions must be Boolean**, so `if (1)` or `if (x)` where `x: Int` will not compile. ### Short-circuiting: `&&` and `||` - `a && b` (logical AND): if `a` is `false`, the result is `false` and **`b` is never evaluated**. - `a || b` (logical OR): if `a` is `true`, the result is `true` and **`b` is never evaluated**. - `!a` is negation. Short-circuiting lets the left operand *guard* the right: ```kotlin if (s != null && s.length > 3) { ... } // safe: length only read when non-null if (cache.isEmpty() || cache.last() == x) { ... } ``` ### Non-short-circuiting: `and`, `or`, `xor` These are **infix member functions** on `Boolean`, not operators, and they **always evaluate both operands**: ```kotlin val r = check1() and check2() // BOTH check functions run, even if check1() is false val x = a or b // both evaluated val differ = a xor b // true iff a != b ``` Use them when you deliberately want every side effect (e.g., run all validators and collect every error), or to avoid branching. Note: there is **no `^` operator** for Boolean in Kotlin — use `xor`. ## Why the difference matters 1. **Side effects:** `if (init() && step())` may skip `step()`; `init() and step()` won't. 2. **Safety/guards:** null/bounds checks rely on `&&`/`||` not evaluating the dangerous right side. 3. **Performance:** `&&`/`||` avoid unnecessary work; `and`/`or` always pay for both. ```kotlin fun loud(tag: String): Boolean { println(tag); return false } val a = loud("L") && loud("R") // prints only L val b = loud("L") and loud("R") // prints L and R ``` ## Related - These are pure operations on `Boolean`; for *bitwise* logic on `Int`/`Long` Kotlin uses the same-named `and`/`or`/`xor`/`shl`/`shr` infix functions. - De Morgan still applies: `!(a && b) == !a || !b`. ## Key takeaways - `&&`/`||` short-circuit; `and`/`or` do not. - Conditions must be `Boolean` — no truthy ints. - Use `and`/`or` only when you truly want both sides evaluated; otherwise prefer `&&`/`||`.

  • When would you intentionally prefer `and` over `&&`?
    When you need both side effects to execute — e.g., run every validator so all errors are recorded — and don't want short-circuiting to skip one.
  • Is there a `^` operator for Boolean XOR in Kotlin?
    No. Use the infix `xor` function for Boolean; `^` is not defined for Boolean.

saying these in an interview costs you the question

  • Saying && and and behave identically
  • Claiming the right side of && always runs
  • Expecting if (someInt) to compile (truthy ints)
  • Using `^` for Boolean XOR
  • Putting a required side effect on the right of && and assuming it executes

context