Reputation: 1183
I am trying to create a constructor in which one of the methods could be passed. See my code:
class Foo(fooMethod: () => Unit, var x: Int, var y: Int) {
def foo() = fooMethod()
}
class Bar(x: Int) extends Foo(() => {
var test1 = x
var test2 = y
println(x + ", " + y)
}, x, 50)
class FieldDemo {
def main(args: Array[String]): Unit = {
val bar = new Bar(40)
bar.foo()
}
}
The in this example val test1 = x
does work, because it is a parameter of the Bar
constructor, but val test2 = y
does not work, even though Bar
extends Foo
and Foo
has a field named y
.
So my question is: why do you not have access to the y
of the Foo
class variable from within the function in Bar
EDIT:
When reading the answer, also look at the first comment by Matheusz Kubuszok and http://ideone.com/9yMpvw vs http://ideone.com/0fDxXe. The second link is the reason why the code in the first link should also fail. I imagine that edge case detection like this would make the compiler way more complex so I now indeed understand why they chose not to allow it.
Upvotes: 2
Views: 555
Reputation: 27595
Basically your code is equivalent to something like:
val barFun(x: Int) = () => {
var test1 = x
var test2 = y
println(x + ", " + y)
}
class Bar(x: Int) extends Foo(barFun(x), x, 50)
When you are creating your lambda, it only sees arguments passed into constructor - it is created within the scope of a constructor, so it has access to variables passed into it as a closure. It does not have access to Foo class as it is not its enclosing class. You can check it if you do something like:
class Bar(z: Int) extends Foo(() => {
var test1 = x
var test2 = y
println(x + ", " + y)
}, z, 50)
You'll see that lambda will have no access to neither x
nor y
. Other test I tried in ammonite shows this:
class Bar(z: Int) extends Foo(() => {
var test1 = Foo.this.x
var test2 = Bar.this.y
}, z, 50)
cmd1.sc:2: Foo is not an enclosing class
var test1 = Foo.this.x
^
cmd1.sc:3: Bar is not an enclosing class
var test2 = Bar.this.y
^
Compilation Failed
As a matter of the fact, this makes sens. At the moment you are creating the lambda, class is not yet initialized. If whatever you do during class initialization had access to all those uninitialized var
s, things could turn nasty.
Upvotes: 3