Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The .. operator in Kotlin is a binary operator used to construct a mathematically closed range, meaning it includes both the defined starting and ending bounds. At compile time, the .. operator is resolved as syntactic sugar for the rangeTo() operator function.

Under the Hood: rangeTo and ClosedRange

When the Kotlin compiler encounters the .. operator, it translates the expression into a method call to rangeTo().
val a = 1
val b = 10
val range1 = a..b

// The compiler translates the above to:
val range2 = a.rangeTo(b)
The rangeTo() function returns an instance of the ClosedRange<T> interface. This interface defines the mathematical boundaries of the range and requires the underlying type T to be Comparable<T>. The ClosedRange<T> interface exposes two properties and two methods:
  • start: T – The lower bound.
  • endInclusive: T – The upper bound.
  • operator fun contains(value: T): Boolean – Evaluates whether a given value falls between the bounds. The interface provides a default implementation for this method (value >= start && value <= endInclusive).
  • fun isEmpty(): Boolean – Evaluates whether the range is empty. The interface provides a default implementation for this method (start > endInclusive).

Type System and Standard Library Implementation

By default, the Kotlin standard library provides an extension function for any type that implements the Comparable<T> interface. This means the .. operator is automatically available for any comparable custom type without requiring explicit operator overloading.
// Conceptual representation of the standard library extension
public operator fun <T : Comparable<T>> T.rangeTo(that: T): ClosedRange<T> = 
    ComparableRange(this, that)

internal class ComparableRange<T : Comparable<T>>(
    override val start: T,
    override val endInclusive: T
) : ClosedRange<T> {
    override fun equals(other: Any?): Boolean { /* ... */ }
    override fun hashCode(): Int { /* ... */ }
    override fun toString(): String { /* ... */ }
}
Unlike a simple anonymous object, the standard library implementation returns a concrete ComparableRange instance. This ensures that standard functions like equals(), hashCode(), and toString() are properly implemented, preventing unexpected behavior when ranges are compared for equality or hashed in collections.

Primitive Specializations

For core integral types (Int, Long, and Char), Kotlin provides highly optimized, specialized range classes: IntRange, LongRange, and CharRange. When the .. operator is used on these primitives, the compiler bypasses the generic ClosedRange<T> allocation and instead instantiates the corresponding specialized class.
val intRange: IntRange = 1..10
val charRange: CharRange = 'a'..'z'
These specialized classes implement both ClosedRange<T> and Iterable<T> (specifically, they inherit from progression classes like IntProgression). This dual implementation allows the range to be iterated over sequentially at the JVM bytecode level using primitive operations, entirely avoiding the memory overhead of boxing and unboxing wrapper types.

Custom Operator Overloading

If a custom type requires a specialized range implementation (for example, a range that is also iterable, similar to IntRange), the .. operator can be explicitly overloaded by defining an operator fun rangeTo member or extension function.
class CustomType(val value: Int) : Comparable<CustomType> {
    override fun compareTo(other: CustomType): Int = this.value.compareTo(other.value)
    
    // Shadows the default Comparable<T>.rangeTo extension function
    operator fun rangeTo(other: CustomType): CustomRange {
        return CustomRange(this, other)
    }
}

class CustomRange(
    override val start: CustomType,
    override val endInclusive: CustomType
) : ClosedRange<CustomType>, Iterable<CustomType> {
    
    // ClosedRange provides default implementations for contains() and isEmpty().
    // Only iterator() is strictly required to satisfy Iterable<T>.
    override fun iterator(): Iterator<CustomType> = object : Iterator<CustomType> {
        private var current = start.value
        
        override fun hasNext(): Boolean = current <= endInclusive.value
        
        override fun next(): CustomType {
            if (!hasNext()) throw NoSuchElementException()
            return CustomType(current++)
        }
    }
}

Floating-Point Behavior

When using the .. operator with floating-point types (Float and Double), the resulting ClosedRange does not implement Iterable. Due to the continuous nature of floating-point numbers, stepping through them sequentially is mathematically undefined without an explicit step value. Therefore, 1.0..2.0 generates a ClosedRange<Double> strictly for boundary checking, not for iteration.
Master Kotlin with Deep Grasping Methodology!Learn More