Pravin Gadakh
Pravin Gadakh

Reputation: 633

scala, IntelliJ: stackoverflow exception

lang.StackOverflow exception in my code, but I think the issue is with IntelliJ rather than the code issue. So here is the deal (pieces of code):

case class Node(data: Int, children: ListBuffer[Node], parents: ListBuffer[Node])

val node1 = Node(thisGuy, ListBuffer[Node](), ListBuffer[Node]())
val node2 = Node(thatGuy, ListBuffer[Node](), ListBuffer[Node](node1))
node1.children.append(node2)

var nodes: mutable.Set[Node] = mutable.Set(node1)
// This is were I am getting stackoverflow exception
nodes.add(node2)

What am I missing here?

EDIT : I suspect this has something to do with toString method. But I am not calling toString method on Node class. Any chance that intellij is calling that method? If so, how to suppress it.

TIA

Upvotes: 0

Views: 204

Answers (2)

Richeek
Richeek

Reputation: 2220

When you add node2 as a child of node1 it creates a circular dependency. If you check what scala compiler generated for it: scalac -Xprint:typer NodeTest.scala

the hashCode function is like this:

override <synthetic> def hashCode(): Int = {
  <synthetic> var acc: Int = -889275714;
  acc = Statics.this.mix(acc, data);
  acc = Statics.this.mix(acc, Statics.this.anyHash(children));
  acc = Statics.this.mix(acc, Statics.this.anyHash(parents));
  Statics.this.finalizeHash(acc, 3)
};

So for node1 to calculate hash code: it needs hash code of node2 (since node2 is a child of node1) and two calculate hash code of node2 it needs hash code of node1 (since node1 is parent of node2)

Why hash code is important here?

Because you are using Set which check if an element already exist before putting it in using hash code.

BTW have you noticed that:

node1.children.append(node2)
node1

Also gives stackoverflow. I am not sure why but looks like toString also has issues with circular dependency.

EDIT: Case classes are generally meant for immutable data structures. So to model what you are trying to achieve you can use class.

class Node(val data: Int) {
   var parents : ListBuffer[Node] =  ListBuffer[Node]()
   var children : ListBuffer[Node] =  ListBuffer[Node]()
}
scala> val node1 = new Node(1)
node1: Node = Node@624ea235

scala> val node2 = new Node(2)
node2: Node = Node@12591ac8

scala> node1.children.append(node2)

scala> node2.parents.append(node1)

Upvotes: 2

Sergii Lagutin
Sergii Lagutin

Reputation: 10671

I suppose you have infinite recursion in equals or hashCode methods because of your class hierarchy. Instances of Node have cyclic references to their parents and children so one of these methods runs infinitely.

Upvotes: 1

Related Questions