0

I'm wondering the result of the piece of code

object localTest {
  def hello = {
    var t = 3
    () => {
      t = t + 3
      println(t)
    }
  }
}
object mainObj {
  def main(args: Array[String]): Unit = {
    val test = localTest.hello
    while (true) {
      Thread.sleep(1000)
      test()
    }
  }
}

Why is the variable t in hello function is only assigned once,and the result will be 6, 9, 12....

I guess this may be related to closure property,but why var t = 3 is only executed once?

Suma
  • 33,181
  • 16
  • 123
  • 191
Jason_typ
  • 3
  • 1

1 Answers1

2

This is not usual functional Scala code, where immutables and vals are prefered over mutability. The style reminds me of Javascript, where things like this are seen very often. Yes, you are correct, this is related to the closure:

  • The hello method defines a scope. In this scope there are two things existing: the t variable and the lambda (the function literal () => {...})
  • The lambda is returned as a return value from the hello method, assigned into the test variable and repeatedly executed by the while loop
  • The lambda is changing the t variable, which is captured in it.

The variable exists in the scope of hello, but as it is captured by the lambda, is it is the same variable used again and again. It is not the hello scope which gets executed from the while loop, rather the lambda body. The hello is executed only once to create the t variable and the lambda.

Expanding the hello definition might help you understand this easier:

val test = {
  var t = 3
  () => {
    t = t + 3
    println(t)
  }
}
while (true) {
  Thread.sleep(1000)
  test()
}

This could be transformed to following code with the same functionality, only the t scope would be expanded so that even the code other than the lambda can see it:

var t = 3
val test = () => {
    t = t + 3
    println(t)
  }
while (true) {
  Thread.sleep(1000)
  test()
}
Suma
  • 33,181
  • 16
  • 123
  • 191
  • Got it, thanks! I think I got stuck on the type of `hello`. I take it as a method definition, which is just an expression. But actually, as you said, it's a function literal. But i'm still confused here. What's the difference between method `hello` and the following one : def hello2() = { println("hi") "test" } when `hello2` is executed in `main`, it will print 'hi' every time – Jason_typ Nov 12 '18 at 07:59
  • 1
    Your new `hello2` is a method to be directly executed. The `hello` from the question contains (and returns as a value) a code to be executed later. See https://en.wikipedia.org/wiki/First-class_function – Suma Nov 12 '18 at 08:03
  • Yes, I understand the difference between Method and Function. Function will be compiled into a Function value object(FunctionN). I used to think the way to define a method is to use 'def' expression. Obviously, I'm wrong. So, when there is a function literal in a Method definition, it will be a function literal, and the function value will be the result of the body code. Am i right? – Jason_typ Nov 12 '18 at 08:12
  • I do not think the distincion between method and function is important here. What is important is functions (both function literals and methods) can be passed as values - anywhere, from functions (as return values) and into the functions (passed as arguments). With lambdas this is obvious, as you create the lambda to be assigned or passed somewhere. In this case the lambda will be the result of the body code, but in other situations is could be assigned or passed. – Suma Nov 12 '18 at 08:36
  • Got it! `val test = localTest.hello val test2 = localTest.hello2()`, `test` and `test2` both are return value(lambda and String). If I directly execute `localTest.hello()`, it will be the function body that is executed. But with `localTest.hello()()`, it will be the return value(lambda) that is executed. Thanks a lot! – Jason_typ Nov 12 '18 at 09:17