Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 553
Knut Arne Vedaa Avatar asked Nov 01 '12 12:11

Knut Arne Vedaa


People also ask

What is an implicit conversion?

An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.

What is implicit conversion give an example?

Implicit conversions: No special syntax is required because the conversion always succeeds and no data will be lost. Examples include conversions from smaller to larger integral types, and conversions from derived classes to base classes.

What is implicit conversion in SQL Server?

Implicit conversions are not visible to the user. SQL Server automatically converts the data from one data type to another. For example, when a smallint is compared to an int, the smallint is implicitly converted to int before the comparison proceeds.

What is an implicit conversion function in Scala?

Implicit conversions in Scala are the set of methods that are apply when an object of wrong type is used. It allows the compiler to automatically convert of one type to another. Implicit conversions are applied in two conditions: First, if an expression of type A and S does not match to the expected expression type B.


1 Answers

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.

like image 132
Malte Schwerhoff Avatar answered Nov 15 '22 04:11

Malte Schwerhoff