Similar problems 1. and 2. mention real problems of forward referencing in scala. But I found this particular simple case where there is no forward referencing. All blocks are perfecly stand-alone.
def testFunction() = {
def recursiveMethod(i: Int, j: Int = 3): Unit = i match {
case 0 => println(s"finished")
case i => recursiveMethod(i-1)
}
val shapes = List[String]()
def recursive(i: Int): Unit = i
}
Solutions to overcome that problem found so far:
shapes
a lazy val (as in 2.)recursive
to something which is not a prefix of recursiveMethod
recursiveMethod
call itself
Can someone explain to me why these are solutions, although they seem to be completely unrelated to the problem?
With -Xprint:typer
you can see the synthetic that is forward-referenced:
package oops {
object Test extends scala.AnyRef {
def <init>(): oops.Test.type = {
Test.super.<init>();
()
};
def testFunction(): Unit = {
def recursiveMethod(i: Int, j: Int = 3): Unit = i match {
case 0 => scala.this.Predef.println(scala.StringContext.apply("finished").s())
case (i @ _) => recursiveMethod(i.-(1), recursiveMethod$default$2)
};
val shapes: List[String] = immutable.this.Nil;
def recursive(i: Int): Unit = {
i;
()
};
<synthetic> def recursiveMethod$default$2: Int @scala.annotation.unchecked.uncheckedVariance = 3;
()
};
def main(args: Array[String]): Unit = ()
}
}
There are at least a couple of tickets related to generating methods close to their origin to avoid these sorts of invisible issues.
Update: for the prurient:
Oldie but goodie
Closer to my heart if not directly related to this problem
I especially liked "rename the function so it's not a prefix of the other function".
This shows how renaming reorders the members:
abstract trait Oops extends scala.AnyRef {
def /*Oops*/$init$(): Unit = {
()
};
def testFunction(): Unit = {
def recursiveMethod(i: Int, j: Int = 3): Unit = i match {
case 0 => scala.this.Predef.println(scala.StringContext.apply("finished").s())
case (i @ _) => recursiveMethod(i.-(1), recursiveMethod$default$2)
};
<synthetic> def recursiveMethod$default$2: Int @scala.annotation.unchecked.uncheckedVariance = 3;
val shapes: List[String] = immutable.this.Nil;
def xrecursive(i: Int): Unit = {
i;
()
};
()
}
};
Needless to add, this must be a bug or a regression. Right?
Update:
Indeed, the sorting test is syntName.toString.startsWith
, which explains why renaming the other function makes a difference. This shows how fragile name mangling leaks bugs everywhere. It's like having termites which, every so often, pop out of the woodwork, reminding you that over the last five years they have compromised the structural integrity of the frame.
This is the code with the comment [Martin] This is pretty ugly.
So it's not unknown, just in need of someone with free time.
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