Operators and Ranges

This section documents Kotlin 2.4.x on the JVM, as published at kotlinlang.org, which is the reference these pages are written and verified against.

This content was generated with the assistance of AI and should be verified against kotlinlang.org before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Kotlin’s arithmetic, comparison, and logical operators read almost identically to Java’s; ranges and infix notation are the two features with no direct Java equivalent.

Arithmetic, Comparison, and Logical Operators

val sum = 5 + 2          // +  -  *  /  %  (same precedence/associativity as Java)
val isEqual = 5 == 2      // structural equality (calls .equals() for objects -- see Equality page)
val isBigger = 5 > 2       // <  >  <=  >=
val both = true && false   // short-circuiting && and ||, plus ! for negation

Every arithmetic and comparison operator is, under the hood, a call to a named function (plus, compareTo, …​) that any type can implement — see Equality and Operator Overloading for the full overloadable set. Kotlin has no bitwise operator symbols (no &, |, ^, <<, >> tokens); the same operations are ordinary infix-notation function calls: x and y, x or y, x xor y, x shl 2, x shr 2, x.inv().

Ranges and Progressions

a..b creates a ClosedRange/IntRange (or the equivalent for Long, Char, etc.) spanning a to b inclusive — there is no dedicated exclusive-range operator token; use until for that instead:

for (i in 1..5) print(i)          // 12345          -- inclusive of 5
for (i in 1 until 5) print(i)     // 1234            -- excludes 5 (equivalent to Java's i < 5)
for (i in 5 downTo 1) print(i)    // 54321           -- descending
for (i in 1..10 step 2) print(i)  // 13579           -- every other value

println(3 in 1..5)                 // true  -- membership test, also usable outside a for loop
println(3 !in 1..5)                // false

A range (or, more generally, a progression — a range plus a step) is a real, iterable object, not just loop syntax — it can be stored in a variable, passed as an argument, or converted to a list with .toList(). in/ !in work as a membership test anywhere a Boolean is expected, including inside a when (see Control Flow).

val workingHours = 9..17
fun isOpen(hour: Int) = hour in workingHours

Infix Notation

A function marked infix can be called without the dot and parentheses — a to b instead of a.to(b) — which is what makes downTo, step, until, and/or/xor/shl/shr (see above), and the Pair-building to ("key" to "value") all read as if they were built-in operators, even though they are ordinary library functions:

infix fun Int.timesRepeated(action: () -> Unit) {
    repeat(this) { action() }
}

3 timesRepeated { println("hi") }   // reads like a sentence

An infix function must take exactly one parameter and be a member or extension function (see Extension Functions and Scope Functions for what an extension function is). This is purely a call-syntax convenience — it compiles to an ordinary method call with no runtime difference from a.timesRepeated { …​ }.

See Also