Home > Back-end >  Property Set of same Class throws Exception StackOverflow in Kotlin
Property Set of same Class throws Exception StackOverflow in Kotlin

Time:09-15

The problem goes away when instead of data class I use simply a class or instead of a MutableSet I use an ArrayList. I am trying to understand what is wrong in the way I first wrote it and can't find anything wrong, but it throws a StackOverflow error when running the last line

data class Person(
    val id : Int,
    val neighbors : MutableSet<Person> = mutableSetOf()
)

fun main() {

    val neighbor1 = Person(0)
    val commonNeighbor = Person(1)
    val neighbor2 = Person(2)
   
    commonNeighbor.neighbors.addAll(listOf(neighbor1,neighbor2))
    neighbor1.neighbors.add(commonNeighbor)
    neighbor2.neighbors.add(commonNeighbor)
}

CodePudding user response:

(Assuming you are using Kotlin/JVM)

The stack trace makes this a lot clearer. Notice that the stack trace is a repetition of calling these two methods.

at bar.Person.hashCode
at java.base/java.util.AbstractSet.hashCode

Let's consider what happens when you add commonNeighbor into neighbour2.neighbours in the final line.

mutableSetOf creates a linked hash set, and in order to be added to a hash set, commonNeighbour needs to be hashed.

An implementation of hashCode is automatically generated for Person because it is a data class, and this is what is used to hash it. This implementation takes into account (i.e. also calls hashCode on) the properties declared in Person's primary constructor, which are id and neighbours.

So to hash commonNeighbours, we need to hash commonNeighbours.id and commonNeighbours.neighbours. What neighbours do commonHeighbours have? neighbour1 and neighbour2. In order to hash them, we need to hash their neighbours too. But wait! One of neighbour1's neighbours is commonNeighbours! We have gone back to where we have started, creating an infinite loop.

All of this wouldn't happen, if the hashCode of Person didn't consider neighbours (which is what making Person a non-data class would do), or if you weren't using a HashSet.

  • Related