Knut Arne Vedaa
Knut Arne Vedaa

Reputation: 15742

Implicit conversion with generic implicit parameter

I seems that combining implicit conversions with generic implicit parameters does not work, as in example 2b below:

object Test {

  case class Foo(i: Int)
  case class Bar(i: Int)
  case class Zip(i: Int)

  object Foo {
    // 1)
    implicit def toBar(foo: Foo)(implicit g: Int => Bar): Bar = g(foo.i)
    // 2)
    implicit def toT[T](foo: Foo)(implicit g: Int => T): T = g(foo.i)
  }

  // 1)
  implicit val b = (i: Int) => Bar(i)
  val bar: Bar = Foo(3)    

  // 2a)
  implicit val z = (i: Int) => Zip(i)
  val zip: Zip = Foo.toT(Foo(3))

  // 2b)
  val zip2: Zip = Foo(3)    // <- compiler error, implicit conversion not applied

}

Is there any theoretical reason why this doesn't work, or is it a limitation of the implementation?

Upvotes: 6

Views: 292

Answers (1)

Malte Schwerhoff
Malte Schwerhoff

Reputation: 12852

For what it's worth, if you run the following reduced version of your code

case class Foo(i: Int)
case class Zip(i: Int)

implicit def toT[T](foo: Foo)(implicit g: Int => T): T = g(foo.i)

implicit val z = (i: Int) => Zip(i)

val zip2: Zip = Foo(3) // <- compiler error, implicit conversion not applied

with -Yinfer-debug, you'll get lots of debug information (Scala 2.9.2) about what is going on behind the scenes. I am not familiar with Scala compiler internals, but the following two output snippets might hint at the problem. The first one is (line 51ff of the gist)

[inferImplicit view] pt = this.Foo => this.Zip
Implicit search in Context(Main.$anon.zip2@ValDef scope=1100551785) {
  search    this.Foo => this.Zip
  target    $anon.this.Foo.apply(3)
  isView    true
  eligible  toT: [T](foo: this.Foo)(implicit g: Int => T)T
}

and I interpret it as "we are looking for an implicit this.Foo => this.Zip and a candidate worth looking at is toT: [T](foo: this.Foo)(implicit g: Int => T)T. This snippet is followed by output that suggests that Scala then tries to instantiate T, but line 81 finally says

inferMethodInstance, still undetermined: List(type T)

My interpretation is, that Scala somehow fails to instantiate T with Zip, which is why the candidate is finally discarded.


That said, I don't see a theoretical problem with your code, and I assume that it is only a shortcoming of the compiler.

Upvotes: 2

Related Questions