Recursive values and laziness

Dear all,
Consider this code:

val a= a + 1
println(a)

I know this called recursive value. How the compiler interpret it? a reference to itself. we do not have
this syntax in Java and we get illegal self reference error.

and this one:

lazy val a:Int = a+ 1
println(a)

in this case i got stack overflow. what’s the difference?
I understand this expression :

val a:LazyList[Int] = 1 #::a

but i don’t understand use case of the former one.

Only the last one really makes any sense.

The first is just plain illegal, as the compiler is saying by giving you an error. You can’t have a val that refers to itself.

The second is technically legal from a syntactic point of view, because a lazy val is sort of like a def that is only computed once. So at runtime it tries to compute a + 1, which means that it needs a, which tells it that it needs to compute a + 1, which means that it needs a, and so on in an infinite recursive loop – hence the stack overflow.

1 Like

In REPL i get the result with no error:

scala> val g:Int = g + 1
val g: Int = 1

Thanks for good explanation

scala> val r:Int = r
^
warning: value r does nothing other than call itself recursively
val r: Int = 0

i think at runtime it gets the value of 0 and recursion terminates.

In runtime, it gets its default value, for an Int it is 0 for anything that extends AnyRef it is null.

1 Like

The problem with val a: Int = a + 1 is that in the REPL and at the top level of a class you are declaring a field and then incrementing its default value, which is absolutely the wrong behavior but that’s what Scala does. It’s more dramatic if you use a reference type.

scala> val s: String = "foo" + s
val s: String = foonull

If you make it lazy then it doesn’t terminate, which isn’t as good as not compiling but at least it’s not wrong.

If you try to do this inside a method (where a is a local variable) then it won’t compile.

In general the answer is that self-referential fields are treacherous in Scala, and the compiler doesn’t help you. The result could be any of:

  • stack overflow
  • null pointer exception
  • infinite loop
  • default value or simple computation thereupon
  • the desired answer

And the only way to know is to try it out. Even very experienced Scala programmers have to mess around with this kind of thing, and the occasional NPE from mutually recursive definitions is pretty common (compile with -Xinit to help diagnose this case).

Anyway, don’t do that. Or be very careful if you do.

4 Likes

Could please bring some reasonable situation in which we should/can use recursive values.
When working with LazyList and so on it’s reasonable but for primitives and so on i don’t know what is the application of it. You mean it’s a useless feature?

It is not a useless feature because how would the compiler knows that it can work for LazyList but not for primitives?

At the end of the day, I can write a lot of code that doesn’t make sense using any features of any language. They have their use case but it is true that in general is very weird to write recursive vals and you need to know that when you do that you need it lazy for it to work.

2 Likes