There appears to be a restriction that you can't use PartialFunction
literals in class constructors:
scala> case class X(a: PartialFunction[Any, Any]) { def this() = this({case x => x}) }
<console>:7: error: Implementation restriction: <$anon: Any => Any> requires premature access to class X.
case class X(a: PartialFunction[Any, Any]) { def this() = this({ case x => x}) }
My first question is why does a partial function literal need access to "this". My second question/observation is that in the Scala REPL, running the same code again crashes the REPL:
scala> case class X(a: PartialFunction[Any, Any]) { def this() = this({ case x => x}) }
java.lang.NullPointerException
at scala.tools.nsc.Global$Run.compileLate(Global.scala:1595)
at scala.tools.nsc.GlobalSymbolLoaders.compileLate(GlobalSymbolLoaders.scala:29)
at scala.tools.nsc.symtab.SymbolLoaders$SourcefileLoader.doComplete(SymbolLoaders.scala:369)
...
And lastly, is there a good workaround for this issue?
Your first question is answered in the comment section of this question
Quoting Imm:
Anonymous classes have access to their enclosing class. The compiler doesn't know that your anonymous partial function doesn't actually access anything (and it would be very hard to check this in full generality); it simply disallows creating any anonymous classes until you're into the class proper.
Why it crashes the REPL is a good question, you should probably submit a ticket to Typesafe with this code example.
A workaround is quite simple, just define the anonymous function outside of the class so the compiler knows the exact state you are closing over:
object X {
val Default: PartialFunction[Any, Any] = { case x => x }
}
case class X(a: PartialFunction[Any, Any]) {
def this() = this(X.Default)
}
Your first question is answered in the comment section of this question.
The issue is that the compiler is too restrictive because it didn't know how to lift stuff out of the constructor parameter block.
The workaround is given in the other answer, which is what the compiler should be doing with that other stuff.
The other workaround is manual construction:
case class X(a: PartialFunction[Any, Any]) { def this() = this({
class $anonfun extends runtime.AbstractPartialFunction[Any, Any] {
override def applyOrElse[A, B >: Any](x: A, default: A => B): B = x match {
case x => x
//case _ => default(x) // completeness
}
override def isDefinedAt(x: Any) = x match {
case x => true
//case _ => false
}
}
new $anonfun()
})
}
The answer to your second question is that it is SI-9170, fixed for 2.11.7.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With