views:

125

answers:

2

Hello,

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
+3  A: 
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")
}
Daniel
but both variations would not be part of ByNameCons and do not know ByNameCons' Methods, so it wouldnt be possible for the passed code to call meth() if ByNameCons { def meth() .. }
hotzen
@hotzen true. I didn't realize you _wanted_ them to be part of `ByNameCons`.
Daniel
+1  A: 

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.

Jackson Davis
same problem as in Daniel's Post, the code is not part of the Class and so is not able to access Coder's methods.
hotzen