views:

168

answers:

3

I saw a delayed example in David Pollak's "Beginning Scala". I tried to adapt that, by trial and error. Here's what I have:

def sayhello() = {
  println("hello")
}

def delaying(t: => Unit):Unit = {
  println("before call")
  t
  println("after call")
}

delaying(sayhello())

How would you delay a function/method that takes parameters? Why can't I use parantheses when I call t? Where can I find more documentation on delaying functions?

+4  A: 

t does not have to be a function value. It is simply any passed-by-name value that evaluates to Unit.

When you state t in the delaying function, you're not explicitly calling the function that was passed as that parameter. By stating it, you are forcing the passed-by-name parameter to be evaluated, which means sayhello() is evaluated at that point.

There's no reason you can't use parameters in functions in passed-by-name parameters:

def say(word: String) {
  println(word)
}

def delaying(t: => Unit) {
  println("before call")
  t
  println("after call")
}

delaying(say("hello"))

The only time you would attach parameters to the t inside delaying would be if its return type was (not Unit but) a function type taking parameters.

Ben James
Can I pass something that returns another type than `Unit`? Or that takes parameters? If so, can you post an example?
Geo
Geo, yes, you can pass any sort of value in a by-name parameter. I have already posted an example in my answer of something that takes parameters: see my `say` function.
Ben James
Oh! Sorry. I think I mentally filtered that :)
Geo
Thanks for your answer! It's great! Is there some official documentation on this? I'm not really sure how to google for it, I tried searching for delayed function calls and Scala, but I didn't find anything relevant.
Geo
Geo, what do you find if you search for "Scala by-name parameter"? I prefer the terms "delayed parameter" or "lazy parameter", but the Scala creators chose "by-name parameter" instead.
Derek Mahar
The term "by-name parameter" may become even more confusing with the introduction of named parameters in Scala 2.8.
Derek Mahar
By name parameter seems to turn up some results. Didn't know the proper name. Thanks Derek!
Geo
Parameters can be passed by name, by value or by reference. This is Computer Science standard. *By name* means the "name" of the parameter is effectively replaced in the function that receives it -- and if it is a whole expression, then that whole expression is replaced in the function that receives the parameter. *By value* means the value of the parameter is copied and passed to the receiving function. *By reference* means a reference to the parameter is passed to the receiving function -- which enables it to change the value in the calling function.
Daniel
Java passes all primitives by value, and all objects as references by value -- ie, the reference to the object is copied and passed, so the object itself can be changed, but not the parameter (variable) in the original function. Scala follows the suit, with the exception of by name parameters.
Daniel
+1  A: 

Since I have a terrible memory and the answer doesn't provide an example how to actually declare a by-name parameter that yields a function taking one or more arguments, I came up with this:

object DelayedEvalTest {

    private class DelayedFunction extends Function1[Int,Unit] {

        override def apply(x:Int) : Unit = {}

        println("function created")
    }

    private def eval(eval:Boolean, op : Int => Unit ) {
        println("in eval()")
        if ( eval ) {
            op( 42 )
        }
    }

    private def evalDelayed(eval:Boolean, op : => Int => Unit ) {
        println("in evalDelayed()")
        if ( eval ) {
            op( 42 )
        }
    }

    def main(args:Array[String]) {
        eval( false , new DelayedFunction() )
        evalDelayed( false , new DelayedFunction() )
    }

}
JavaGuy