By-name or not by-name; when using what?

Let’s say we have an error handler that calls a callback upon finishing the error handling business.

Let the callback be something like that:

def callback(result: Result): Unit = ???

Now the signature of the error handler could be either:

def handleError(error: Error, callback: Result => Unit): Unit = ???

or:

def handleError(error: Error, callback: => Result => Unit): Unit = ???

To me, there is no difference at execution-time, at least as far as I can tell.

Are there any differences, in this case, I should consider? Which variant is the better/more Scala-like way to go?

Hi.

Usually, passing a function as a by-name argument does not make much sense (except if computing the function itself is somehow expensive) since the sole purpose of a by-name parameter is to defer evaluating an argument to a function at a later time, or not at all at the discretion of the called function.

When using a by-name parameter, the compiler wraps the given argument in a function on its own and using the parameter inside the body of the user-defined function calls the auto-generated function each time to retrieve the value. So, one has to be careful to not evaluate the by-value parameter more than once, unless desired. The idiom usually seen is:

def foo(param: => Int): Unit = {
  lazy val paramValue = param

  ... // only use paramValue from now on...
}

Note that there is indeed a difference at execution time, as I tried to explain. So the second form of your error handling actually looks like this:

def handleError(error: Error, callback: () => (Result => Unit)): Unit = ???

ie. it is a 0-arity function returning a function accepting a Result as argument, only for side-efffects.

3 Likes

However (=> Result) => Unit might make more sense. Note that you then have a function that itself accepts a by-name argument. A function like that might be used when you want to give the callback control over whether Result should be computed or not, e.g. when it’s very expensive to compute but sometimes the callback doesn’t need it.

1 Like