coming from my other question is there a way to get by-name-parameters for constructors working? I need a way to provide a code-block which is executed on-demand/lazy/by-name inside an object and this code-block must be able to access the class-methods as if the code-block were part of the class.
Following Testcase fails:
package test
class ByNameCons(code: => Unit) {
def exec() = {
println("pre-code")
code
println("post-code")
}
def meth() = println("method")
def exec2(code2: => Unit) = {
println("pre-code")
code2
println("post-code")
}
}
object ByNameCons {
def main(args: Array[String]): Unit = {
val tst = new ByNameCons {
println("foo")
meth() // knows meth() as code is part of ByNameCons
}
tst.exec() // ByName fails (executed right as constructor)
println("--------")
tst.exec2 { // ByName works
println("foo")
//meth() // does not know meth() as code is NOT part of ByNameCons
}
}
}
Output:
foo
method
pre-code
post-code
--------
pre-code
foo
post-code
This is because when you're making an instance like this:
val tst = new ByNameCons {
...
}
.. you're actually creating an anonymous class, like in java.
The above code is the same as:
val tst = new ByNameCons() { ... }
.. while the correct syntax for passing by-name is:
val tst = new ByNameCons( { ... } )
You cant omit parentheses the same way for constructors as with functions.
val tst = new ByNameCons( {
println("foo")
} )
Thought it is probably just easier to do this:
object ByNameCons {
def apply(code: => Unit) = new ByNameCons(code)
}
val tst = ByNameCons { // no "new" here -- can't mix traits either
println("foo")
}
I dont know why, but it appears that using {} or () when creating the class changes the behavior. Using the following class,
class Coder(code: => Unit) {
def exec = {
println("before")
code
println("after")}
}
}
scala> val brackets = new Coder {println("testing")}
testing
brackets: Coder = $anon$1@1af7a03
scala> brackets exec
before
after
Now instead if defined another way,
scala> val parens = new Coder(println("testing"))
parens: Coder = Coder@dca3ed
scala> parens exec
before
testing
after
as desired. It seems as if in the first notation, the compiler is interpreting the brackets as a block to be evaluated to Unit
, instead of an anonymous function which, when called, evaluates to Unit
.
FWIW, using ({ ... }) also works fine.