Home > OS >  Why does an implicit with a map yield a Range statement error?
Why does an implicit with a map yield a Range statement error?

Time:12-12

With the below MRE I would expect the following output:

$ scala mre.scala
1
object Main {
  def main(args: Array[String]): Unit = {
    implicit val thing = List[String]().map(_.to(List))
    for (x <- 1 to 1) {
        println(x)
    }
  }
}

However what I do get is the following

$ scala mre.scala
mre.scala:4: error: type mismatch;
 found   : Int(1)
 required: scala.collection.Factory[Char,?]
    for (x <- 1 to 1) {

If I remove either the implicit or the .map(_.to(List)) then it works as expected.

What on earth is going on here? I have no idea where to even begin.

$ scala --version
Scala code runner version 2.13.7 -- Copyright 2002-2021, LAMP/EPFL and Lightbend, Inc.

CodePudding user response:

An educated guess (sth like 99% of certainty): any collection extends (Partial)Function therefore by making collection implicit you are providing an implicit conversion (because any unary implicit def OR implicit function is implicit conversion):

// this
implicit val thing = List[String]().map(_.to(List))
// implies this
implicit def intToCharList(idx: Int): List[Char]] =  thing(idx)

Then here:

 1 to 1

you have ambiguity: it might be either:

  • extension method .to(Int) on Int
  • normal method .to(CollectionType) on List (since Scala 2.13) after Int is implicitly converted

If compiler picks the latter, then you have something like

thing(1).to(1) // .to expects collection factory and got 1 instead 

which triggers the error that you see. And it might pick the latter because you declared your implicit in the same scope and richInt implicit conversion is declared in LowPriorityImplicit in scala.Predef, so Scala will prefer yours.

In Scala 3 implicit conversions are a subtype of Function so this issue is not happening. In Scala 2 I can only strongly recommend against making any collection implicit.

  • Related