A following code is giving me an error with Scala 2.11.7 which is confusing to me:
class A(val a: String, val bVal: Option[String] = None) {
val b: String = bVal.getOrElse("")
def copy(a: String = a, b: Option[String] = Some(b)) = new A(a, b)
}
The IntelliJ IDE is not showing any error, but on compile I get an error:
Error:(4, 52) type mismatch;
found : Option[String]
required: String
def copy(a: String = a, b: Option[String] = Some(b)) = new A(a, b)
^
For comparison, this compiles fine:
class A(val a: String, val bVal: Option[String] = None) {
val b = bVal
def copy(a: String = a, b: Option[String] = Some(b.getOrElse(""))) = new A(a, b)
}
When I replace Some(b)
with Some(this.b)
, the error goes away, but it is still confusing to me why the error is there in first place. It looks like the compiler is resolving the b
in the Some
as the parameter of copy
, not the b
member of A
. If this is the case, how can the second version compile without error?
This has got to be a bug. The scope of the default expression includes previous param lists.
scala> def x = 1
x: Int
scala> def f(x: Int = x) = 2 * x
f: (x: Int)Int
scala> f()
res0: Int = 2
and -Xprint:typer
shows the default is correct:
class A extends scala.AnyRef {
<paramaccessor> private[this] val a: String = _;
<stable> <accessor> <paramaccessor> def a: String = A.this.a;
<paramaccessor> private[this] val bVal: Option[String] = _;
<stable> <accessor> <paramaccessor> def bVal: Option[String] = A.this.bVal;
def <init>(a: String, bVal: Option[String] = scala.None): A = {
A.super.<init>();
()
};
private[this] val b: String = A.this.bVal.getOrElse[String]("");
<stable> <accessor> def b: String = A.this.b;
def copy(a: String = a, b: Option[String] = scala.Some.apply[A](<b: error>)): A = new $iw.this.A(a, b);
<synthetic> def copy$default$1: String = A.this.a;
<synthetic> def copy$default$2: Option[String] = scala.Some.apply[String](A.this.b)
};
<synthetic> object A extends AnyRef {
def <init>(): A.type = {
A.super.<init>();
()
};
<synthetic> def <init>$default$2: Option[String] = scala.None
}
Yup.
scala> def y = "hi"
y: String
scala> def g(x: String)(y: Option[String] = Some(x)) = y map (_ * 2)
g: (x: String)(y: Option[String])Option[String]
scala> g("bye")()
res0: Option[String] = Some(byebye)
scala> def g(x: String)(y: Option[String] = Some(y)) = y map (_ * 2)
<console>:11: error: type mismatch;
found : Option[String]
required: String
def g(x: String)(y: Option[String] = Some(y)) = y map (_ * 2)
^
Edit: the fact that the default method is correct doesn't mean much, since there are puzzlers related to the fact that the default methods are not very hygienic. E.g., http://scalapuzzlers.com/#pzzlr-051