Question

The following code does not compile. Desired is to have a call-by-name constructor parameter in an implicit class as illustrated here,

def f(n: Int) = (1 to n) product

implicit class RichElapsed[A](val f: => A) extends AnyVal {

  def elapsed(): (A, Double) = {
    val start = System.nanoTime()
    val res = f
    val end = System.nanoTime()

    (res, (end-start)/1e6)
  }

}

where a call

val (res, time) = f(3).elapsed
res: Int = 6
time: Double = 123.0

This error is reported in REPL,

<console>:1: error: `val' parameters may not be call-by-name
       implicit class RichElapsed[A](val f: => A) extends AnyVal {

Thus to ask how RichElapsed class could be refactored.

Thanks in Advance.

Was it helpful?

Solution

Peter Schmitz's solution to simply drop the val (along with the hope of turning RichElapsed into a value class) is certainly the simplest and least intrusive thing to do.

If you really feel like you need a value class, another alternative is this:

class RichElapsed[A](val f: () => A) extends AnyVal {

  def elapsed(): (A, Double) = {
    val start = System.nanoTime()
    val res = f()
    val end = System.nanoTime()

    (res, (end-start)/1e6)
  }
}

implicit def toRichElapsed[A]( f: => A ) = new RichElapsed[A](() => f )

Note that while using a value class as above allows to remove the instantiation of a temporary RichElapsed instance, there is still some wrapping going on (both with my solution and with Peter Schmitz's solution). Namely, the body passed by name as f is wrapped into a function instance (in Peter Schmitz's case this is not apparent in the code but will happen anyway under the hood). If you want to remove this wrapping too, I believe the only solution would be to use a macro.

OTHER TIPS

Do it without val as the error messages demands and then you also have to abandon the AnyVal since a value class needs to have exactly one public val:

implicit class RichElapsed[A](f: => A)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top