Goktug
Goktug

Reputation: 923

Reference and Value Comparison

Actually, I am new to kotlin; therefore, this question may be very basic.

According to kotlin documentation, two variables can be compared with === and == operators. First one ('==') checks if they have same content or not, and the second one ('+==') checks if they have same reference or not. However, I cannot find any built-in class whose objects have same content, but with different references.

var str1 : String = "Hello World"
var str2 : String = "Hello World"

if( str1 == str2 ){ // yes
   print("Their contents are same\n")
{

if( str1 === str2 ){ // yes
   print("Their references are same\n")
}

Instances of all classes I have encountered up to now have same reference if their contents are same. How do we define two objects which have same content, but different references ?

Upvotes: 1

Views: 502

Answers (3)

miensol
miensol

Reputation: 41598

Reference equality

Referential equality is checked by the === operation (and its negated counterpart !==). a === b evaluates to true if and only if a and b point to the same object.

In other words the === operator compares if a and b are the same reference. Using it on some basic types can be misleading because of:

An example would be:

val a:Int? = 123
val b:Int? = 123
println(a === b) // => true

val c:Int? = 130
val d:Int? = 130
println(c === d) // => false

Obviously in both cases the a == b and c == d is true.

Since string interning is also possible at compile time the === also returns true in simple scenarios:

val a = "ala"
val b = "ala"
println(a === b) // => true

val c = "!ala".substring(1)
val d = "!ala".substring(1)
println(c === d) // => false

Structural equality

Structural equality is checked with the == operator (and its negated counterpart !=). By convention, an expression like a == b is translated to:

a?.equals(b) ?: (b === null)

As we saw above it is perfectly normal for built-in classes like String and Int to return false for reference equality === even though their contents are equal. Kotlin lets us define classes which can easily be checked for structural equality with data classes like so:

data class Address(val city:String, val street1:String)

val a = Address("Warsaw", "Jagielońska")
val b = Address("Warsaw", "Jagielońska")

println(a === b) // => false
println(a == b) // => true

Upvotes: 3

Amit Bhati
Amit Bhati

Reputation: 5649

The === is not working because of the way you are defining the String. If you create a string using a literal, it will point to the same String in the String pool.

var str1 = "Hello World"
    var str2 = "Hello World"
    val str3 = buildString { "Hello World" }
    val str4 = buildString { "Hello World" }

    var result = str1===str2 // true
    println(result)

    result = str1 == str2 // true
    println(result)

    result = str3 === str4 // false
    println(result)

    result = str3 == str4 // true
    println(result)

Upvotes: 2

zsmb13
zsmb13

Reputation: 89528

Comparing String references like that will return true, because the JVM optimizes your example code by reusing the first String instance, since it's immutable anyway. See more discussion about this here, for example.

If you call the constructor of a class directly however, you'll skip any optimizations, and get different instances:

val i1 = Integer(1)
val i2 = Integer(1)

println(i1 == i2)  // true
println(i1 === i2) // false

Sidenote: in Java, I'd have shown this example with new String("Hello world"), but apparently the Kotlin String class doesn't have a constructor of that form. Strange.

Upvotes: 2

Related Questions