Reputation: 4189
I implement a Scala class with an overloaded method that can take an Iterable[String]
or a String*
varargs parameter:
class StackOverflow(names: Iterable[String]) {
// This function creates a copy of the StackOverflow object
// copy is needed but this cannot be a case class.
private def copy(names: Iterable[String] = names) = new StackOverflow(names) // <- line 19
// overloaded methods
def withNames(names: Iterable[String]) = this.copy(names = names) // <- line 24
def withNames(names: String*) = require(names.nonEmpty); withNames(names.toIterable) // <- line 26
}
object App {
def main(args: Array[String]) = {
val x1 = new StackOverflow(Seq("a", "b"))
val x2 = x1.withNames("c", "d")
}
}
I expect x2
to be a new object with names c
and d
, but the value x2
cannot be created because of an infinite recursion causing a StackOverflowError:
Exception in thread "main" java.lang.StackOverflowError
at scala.collection.LinearSeqLike$class.thisCollection(LinearSeqLike.scala:48)
at scala.collection.immutable.List.thisCollection(List.scala:84)
at scala.collection.immutable.List.thisCollection(List.scala:84)
at scala.collection.IterableLike$class.toIterable(IterableLike.scala:87)
at scala.collection.AbstractIterable.toIterable(Iterable.scala:54)
at test.StackOverflow.<init>(StackOverflow.scala:26)
at test.StackOverflow.copy(StackOverflow.scala:19)
at test.StackOverflow.withNames(StackOverflow.scala:24)
at test.StackOverflow.<init>(StackOverflow.scala:26)
at test.StackOverflow.copy(StackOverflow.scala:19)
at test.StackOverflow.withNames(StackOverflow.scala:24)
...
What's wrong with the code?
Upvotes: 1
Views: 346
Reputation: 6092
You have been trapped by the omission of braces.
You don't even need the val x2 = x1.withNames("c", "d")
line.
def withNames(names: String*) = require(names.nonEmpty); withNames(names.toIterable)
This is actually:
def withNames(names: String*) = require(names.nonEmpty) // part of class
withNames(names.toIterable) // part of constructor
withNames(names.toIterable)
is absolutely correct, since names
is also a field in your class.
As a result, whenever you instantiate a StackOverflow object, the constructor calls withNames()
that creates a new instance, that calls withNames()
and so on. To fix this, you must use braces around the method definition. And of course, since you are overloading withNames() you must specify the return type as well.
Upvotes: 6