Bug? Memoized function doesn't compile inside closure

I get “Error: forward reference extends over definition of value bar” for this code

case class Memo[A,B](f: A => B) extends (A => B) {
	val hashTable = scala.collection.mutable.Map.empty[A,B]
	def apply(x: A) = hashTable.getOrElseUpdate(x, f(x)) 
}

def foo = {
	val bar: Memo[Int, Int] = Memo {n => bar(n-1)} // Error here
	bar(0)
}

The code compiles if I move bar out of foo. I use Scala IDE 4.6 with Scala 2.12.2.

This behavior is completely expected and consistent with the scoping rules of the language. You are using bar in its declaration. This won’t work for a local variable as you have in this code. The reason it compiles if you move it outside of foo is that it becomes a class-level member, where you have different scoping rules. Members of classes are in scope before the point of their declaration while local variables aren’t. However, if a member is referenced before the execution reaches the point of initialization, it will have a default value, which in the case of an AnyRef, is null.

So that means that values can be recursive only if they are class members? Which is different from functions defined with def.

I don’t really know if I have a complete explanation. You can have a recursive val in a method if it is declaring a function. For example:

val fact: Int => Int = n => if (n<2) 1 else n*fact(n-1)

This is perfectly happy inside of a method. I don’t know if this is a special case in the compiler. In theory, what you are doing could work similarly, because bar is only referenced inside of a lambda expression, but the compiler might have a harder time recognizing that.

Your code compiles if bar is a def declaration instead of a val declaration, but that produces very different code that isn’t really doing what you want.