Why in this case conversion is not implied?

I have the following code in Scala. Say there is an implicit conversion of A to B. Why is my implicit List [A] to List [B] not working?

object ImplicitTest {    
  case class CaseClassA(a: String)
  case class CaseClassB(b: String)

  implicit def a2b(a: CaseClassA): CaseClassB = CaseClassB(a.a)

  implicit def listImplicitConversion[A, B](l: List[A])(implicit conv: A => B): List[B] = l.map(conv)

  def main(args: Array[String]) {
    val listOfA: List[CaseClassA] = List(CaseClassA("a"))
    val listOfB: List[CaseClassB] = listOfA
  }
}

Compiling this code results in the following error:

Error:(14, 37) type mismatch;
 found   : List[ImplicitTest.CaseClassA]
 required: List[ImplicitTest.CaseClassB]
    val listOfB: List[CaseClassB] = listOfA
+4
source share
2 answers

This is a mistake, namely SI-10405 , which I discovered a while ago.

For some reason Predef, implicit search fails. If you compile your code with a flag -Yno-predef, you will succeed.

The symptom is that you see typer trying to resolve implicit using Predef.conforms[A]compilation in -Xlog-implicits:

λ scalac -Xlog-implicits Bar.scala
Bar.scala:16: listImplicitConversion is not a valid implicit value for List[yuval.tests.ImplicitTest.CaseClassA] => List[yuval.tests.ImplicitTest.CaseClassB] because:
incompatible: (l: List[yuval.tests.ImplicitTest.CaseClassA])(implicit conv: yuval.tests.ImplicitTest.CaseClassA => yuval.tests.ImplicitTest.CaseClassA)List[yuval.tests.ImplicitTest.CaseClassA] does not match expected type List[yuval.tests.ImplicitTest.CaseClassA] => List[yuval.tests.ImplicitTest.CaseClassB]
    val listOfB: List[CaseClassB] = listOfA

And ignores further search, although earlier he managed to match:

|-- List[CaseClassB] TYPEmode (site: value listOfB in ImplicitTest)
|    |    |    |    |    |-- scala.`package` EXPRmode-POLYmode-QUALmode (site: value listOfB in ImplicitTest)
|    |    |    |    |    |    \-> scala.type
|    |    |    |    |    |-- CaseClassB TYPEmode (site: value listOfB in ImplicitTest)
|    |    |    |    |    |    \-> yuval.tests.ImplicitTest.CaseClassB
|    |    |    |    |    \-> List[yuval.tests.ImplicitTest.CaseClassB]
|    |    |    |    |-- listOfA : pt=List[yuval.tests.ImplicitTest.CaseClassB] BYVALmode-EXPRmode (site: value listOfB in ImplicitTest)
|    |    |    |    |    [search #2] start `List[yuval.tests.ImplicitTest.CaseClassA]`, searching for adaptation to pt=List[yuval.tests.ImplicitTest.CaseClassA] => List[yuval.tests.ImplicitTest.CaseClassB] (silent: value listOfB in ImplicitTest) implicits disabled
|    |    |    |    |    [search #2] considering listImplicitConversion
|    |    |    |    |    |-- listImplicitConversion BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value listOfB in ImplicitTest) implicits disabled
|    |    |    |    |    |    [adapt] [A, B](l: List[A])(implicit conv: A => B)List[B] adapted to [A, B](l: List[A])(implicit conv: A => B)List[B]
|    |    |    |    |    |    \-> (l: List[A])(implicit conv: A => B)List[B]
|    |    |    |    |    solving for (A: ?A, B: ?B)
|    |    |    |    |    [search #3] start `[A, B](l: List[A])(implicit conv: A => B)List[B]` inferring type B, searching for adaptation to pt=yuval.tests.ImplicitTest.CaseClassA => B (silent: value listOfB in ImplicitTest) implicits disabled
|    |    |    |    |    [search #3] considering a2b
|    |    |    |    |    |-- { ((a: yuval.tests.ImplicitTest.CaseClassA) => ImplicitTe... : pt=yuval.tests.ImplicitTest.CaseClassA => ? EXPRmode (silent: value listOfB in ImplicitTest) implicits disabled
|    |    |    |    |    |    |-- ((a: yuval.tests.ImplicitTest.CaseClassA) => ImplicitTest... : pt=yuval.tests.ImplicitTest.CaseClassA => ? EXPRmode (silent: value listOfB in ImplicitTest) implicits disabled
|    |    |    |    |    |    |    |-- ImplicitTest.this.a2b(a) EXPRmode (silent: value $anonfun in ImplicitTest) implicits disabled
|    |    |    |    |    |    |    |    |-- ImplicitTest.this.a2b BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value $anonfun in ImplicitTest) implicits disabled
|    |    |    |    |    |    |    |    |    \-> (a: yuval.tests.ImplicitTest.CaseClassA)yuval.tests.ImplicitTest.CaseClassB
|    |    |    |    |    |    |    |    |-- a : pt=yuval.tests.ImplicitTest.CaseClassA BYVALmode-EXPRmode (silent: value $anonfun in ImplicitTest) implicits disabled
|    |    |    |    |    |    |    |    |    \-> yuval.tests.ImplicitTest.CaseClassA
|    |    |    |    |    |    |    |    \-> yuval.tests.ImplicitTest.CaseClassB
|    |    |    |    |    |    |    \-> yuval.tests.ImplicitTest.CaseClassA => yuval.tests.ImplicitTest.CaseClassB
|    |    |    |    |    |    \-> yuval.tests.ImplicitTest.CaseClassA => yuval.tests.ImplicitTest.CaseClassB
|    |    |    |    |    [adapt] a2b adapted to { ((a: yuval.tests.ImplicitTest.CaseClassA) => ImplicitTe... based on pt yuval.tests.ImplicitTest.CaseClassA => B
|    |    |    |    |    [search #3] solve tvars=?B, tvars.constr= >: yuval.tests.ImplicitTest.CaseClassB
|    |    |    |    |    solving for (B: ?B)
|    |    |    |    |    [search #3] success inferred value of type yuval.tests.ImplicitTest.CaseClassA => =?yuval.tests.ImplicitTest.CaseClassB is SearchResult({
|    |    |    |    |      ((a: yuval.tests.ImplicitTest.CaseClassA) => ImplicitTest.this.a2b(a))
|    |    |    |    |    }, TreeTypeSubstituter(List(type B),List(yuval.tests.ImplicitTest.CaseClassB)))

, :

[search #3] success inferred value of type yuval.tests.ImplicitTest.CaseClassA => =?yuval.tests.ImplicitTest.CaseClassB is SearchResult({
  ((a: yuval.tests.ImplicitTest.CaseClassA) => ImplicitTest.this.a2b(a))
}, TreeTypeSubstituter(List(type B),List(yuval.tests.ImplicitTest.CaseClassB)))
+4

, - . , implicit conversion , , .

1:

val listOfA: List[CaseClassA] = List(CaseClassA("a"))
val listOfB: List[CaseClassB] = listOfA.convert  //this assignment will fail.

val listOfB: List[CaseClassB] = List(CaseClassA("a"))    //will work

2: a2b listImplicitConversion . , , - a2b. - listImplicitConversion A => B. , a2b type CaseClassA => CaseClassB - . , , . (, - 1 ?)

implicit def listImplicitConversion[A, B](l: List[A])(implicit conv: CaseClassA => CaseClassB): List[B] = l.map(e=>{conv(e.asInstanceOf[CaseClassA]).asInstanceOf[B]})

, :

case class ImplicitWrapper[A,B](fn:A=>B)
implicit val a2bWrapper = ImplicitWrapper(a2b)
implicit def listImplicitConversionV2[A,B](l: List[A])(implicit convWrapper: ImplicitWrapper[A,B]):List[B] = l.map(convWrapper.fn)
  val listOfA: List[CaseClassA] = List(CaseClassA("a"))
  val listOfB: List[CaseClassB] = listOfA    //will work. 

3: .

  implicit class listImplicitConversion[A, B](l: List[A]) {
    def convert(implicit conv: A => B): List[B] = l.map(conv)
  }
  val listOfA: List[CaseClassA] = List(CaseClassA("a"))
  val listOfB: List[CaseClassB] = listOfA.convert    //will work
0

Source: https://habr.com/ru/post/1696102/


All Articles