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 is the referential inequality operator in Kotlin. It evaluates to true if two object references point to different memory locations (i.e., they are distinct instances), and false if they point to the exact same instance in memory. It serves as the strict negation of the referential equality operator (===).

Syntax and Translation

The operator is placed between two references:
a !== b
At compile time, Kotlin translates this expression directly to the negation of a reference check. It does not invoke any methods on the objects.
// Conceptual translation
!(a === b)

Referential vs. Structural Inequality

It is critical to distinguish !== from the structural inequality operator (!=).
  • != (Structural Inequality): Evaluates whether the content or state of two objects differs. It is translated to !(a?.equals(b) ?: (b === null)).
  • !== (Referential Inequality): Bypasses the equals() method entirely. It strictly compares the memory addresses of the references on the heap.
class DataNode(val id: Int) {
    override fun equals(other: Any?): Boolean {
        return other is DataNode && this.id == other.id
    }
}

val nodeA = DataNode(1)
val nodeB = DataNode(1)
val nodeC = nodeA

// Structural comparison (evaluates equals())
println(nodeA != nodeB)  // false: Contents are identical

// Referential comparison (evaluates memory addresses)
println(nodeA !== nodeB) // true: They are distinct objects in memory
println(nodeA !== nodeC) // false: They point to the exact same object

Behavior with Primitives and Boxing

In Kotlin 1.6 and later, using identity equality operators (=== and !==) on unboxed primitive types (such as Int, Double, Boolean) results in a strict compilation error. This is because JVM primitives are passed by value and do not possess object identity. However, when these types are boxed (e.g., forced into an object wrapper via nullable types like Int? or generic type parameters), !== evaluates the references of the boxed objects on the heap. This behavior is subject to JVM memory optimizations, such as the Integer cache.
// Unboxed primitives
val x: Int = 1000
val y: Int = 1000
// COMPILATION ERROR: Identity equality for arguments of types Int and Int is forbidden
println(x !== y) 

// Boxed primitives (Nullable)
val boxedX: Int? = 1000
val boxedY: Int? = 1000
println(boxedX !== boxedY) // true: Distinct boxed object references on the heap

// Boxed primitives within JVM cache range (-128 to 127)
val cachedX: Int? = 42
val cachedY: Int? = 42
println(cachedX !== cachedY) // false: JVM reuses the same cached object reference

Restrictions with Value Classes

Applying referential equality operators (=== and !==) to value (inline) classes is strictly forbidden in Kotlin and results in a compilation error. Because the Kotlin compiler optimizes value classes by unpredictably boxing or unboxing their underlying data at runtime, they do not possess a guaranteed, stable object identity. Consequently, evaluating memory addresses for these types is semantically invalid.
@JvmInline
value class Identifier(val id: String)

val id1 = Identifier("user_123")
val id2 = Identifier("user_123")

// COMPILATION ERROR: Identity equality for arguments of types Identifier and Identifier is forbidden
println(id1 !== id2) 
Master Kotlin with Deep Grasping Methodology!Learn More