3

Consider following code snippet:

object Example {

    def run(f: => Unit): Unit = {
        implicit val i = 1

        f
    }

    def caller(): Unit =
        run {
            todo
        }

    def todo(implicit i: Int): Unit =
        println(i)
} 

which currently is not compiling with following message:

Error:(14, 13) could not find implicit value for parameter i: Int
            todo
        ^ 

My question is it possible to make implicit parameter available to call-by-name function body?

EDIT I tried make it working with macro implementation as suggested by Alexey Romanov

import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context

object Macros {

  def run(f: => Unit): Unit = macro runImpl

  def runImpl(c : Context)(f: c.Tree) = {
      import c.universe._
      q"""{
        implicit val i: Int = 3
        $f
      }"""
  }
}

object Example extends App {

    Macros.run {
       todo
    }

    def todo(implicit i: Int): Unit =
       println(i)

}

Debugging macro i can see that it is correctly expanded into

{
   implicit val i: Int = 3
   Example.this.todo
}

Unfortunately it does not compiles as well with same error that implicit is not found.

Digging into issue i found discussions here and jira issues https://issues.scala-lang.org/browse/SI-5774

So question is the same: Is it possible to tunnel implicit into todo function in this case?

llirik
  • 148
  • 7
  • `def caller()(implicit i: Int)` or `todo(parameter)`? – Reactormonk Sep 20 '15 at 17:49
  • It is clear that i can pass implicit as parameter like `todo(parameter)`, but in this case whole point of implicit disappears. My question was more about why implicit defined in `run` is not tunneled into caller`s run body. – llirik Sep 20 '15 at 18:09

2 Answers2

0

Simply said - no. implicit requires that it is obvious from the code what is going on. If you want anything to be passed to a function implicitly, it must have implicit parameter which is not the case of your f function.

This is a great source of wisdom related to implicit: http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html

Rado Buransky
  • 3,252
  • 18
  • 25
  • It is possible to define `f: implicit? => Unit`? – llirik Sep 20 '15 at 18:18
  • You can do it like this: `f: ()(implicit i: Int) => Unit`. But then you have to call `f` with parens like `f()` instead of call-by-name. – Rado Buransky Sep 20 '15 at 18:21
  • 1
    Can you be more specific? If i change to `f: ()(implicit i: Int) => Unit` as you suggested IDE complains that it is not valid function definition – llirik Sep 20 '15 at 18:39
0

My question was more about why implicit defined in run is not tunneled into caller's run body

Because that's simply not how lexical scoping works. It isn't in scope where the body is defined. You have two good alternatives:

  1. def run(f: Int => Unit) = f(1)
    
    run { implicit i => 
      todo // can use i here
    }
    
  2. Make run a macro. This should be at least an approximation (adapted from SI-5778), unfortunately I can't test it at the moment:

    object Macros {
      def run(f: => Unit) = macro runImpl
    
      def runImpl(c : Context)(f: c.Tree) = q"""{
        implicit val i: Int = 1
        // some other implicits
        $f
      }"""
    }
    
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • First option is exactly what i have now, the problem tough if i now have `f: (Int, String) => Unit` i cannot use `run { implicit i =>` to make both params available as implicits i would need `run { (a,b) => implicit val aa = a; implicit bb = b ...` which in case of dsl become boilerplate code. How would macros help me here? – llirik Sep 20 '15 at 18:28
  • I still do not understand how making `run` a macro will solve implicit not found issue in `caller`. Can you elaborate on this? – llirik Sep 20 '15 at 18:53
  • If you make the argument a `c.Tree`, the macro expansion will happen before type checking, implicit search, etc. So you just insert the implicits you want and they will be available by the time they are needed. See the edited answer. – Alexey Romanov Sep 20 '15 at 18:55
  • Unfortunately it does not work either, with same error. I found issue was discusses on scala internal https://groups.google.com/forum/#!topic/scala-internals/zvY_FR3hdJQ but looks like this is still not fixed (implicits defined in macros are now added/findable) – llirik Sep 20 '15 at 19:40