Name Parameters for By-Name Constructors

Coming from my other question , is there a way to get by-name parameters for working constructors? I need a way to provide a codeblock that is requested / lazy / by-name within an object, and that codeblock should be able to access the method classes as if the codeblock was part of a class.

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

      

+2


a source to share


3 answers


This is because when you make an instance like this:

val tst = new ByNameCons {
  ...
}

      

.. you are actually creating an anonymous class like in java. The above code is the same as:

val tst = new ByNameCons() { ... }

      



.., whereas the correct syntax for passing by name is:

val tst = new ByNameCons( { ... } )

      

You cannot omit parentheses in the same way for constructors as you can for functions.

+5


a source


val tst = new ByNameCons( {
   println("foo")  
} )

      

Thought it might just be simpler:



object ByNameCons {
  def apply(code: => Unit) = new ByNameCons(code)
}

val tst = ByNameCons { // no "new" here -- can't mix traits either
  println("foo")
}

      

+3


a source


I don't know why, but it seems that when using the class {} or (), the behavior changes when the class is created. 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 if defined otherwise,

scala> val parens = new Coder(println("testing"))
parens: Coder = Coder@dca3ed
scala> parens exec
before
testing
after

      

optional. It seems that in the first notation, the compiler interprets the parentheses as a block to be evaluated as Unit

, instead of an anonymous function, which, when called, evaluates as Unit

.

FWIW using ({...}) also works great.

+1


a source







All Articles