Home > OS >  Where is implicit function for flatten defined?
Where is implicit function for flatten defined?

Time:09-11

flatten is defined as:

override def flatten[B](implicit toIterableOnce: A => IterableOnce[B])

My code is:

val myList = List(1,2,3)
println(myList.map(x => List(x, 2*x)).flatten)

So if I understand it correctly, when I call flatten I need an implicit function defined somewhere and this function takes List[Int] as input and returns IterableOnce[Int].

I haven't defined any such function and code works fine, so implicit is found somewhere. How can I find where its exactly defined? I was expecting it in Predef, but seems its not there.

CodePudding user response:

If you do

// libraryDependencies  = scalaOrganization.value % "scala-reflect" % scalaVersion.value
import scala.reflect.runtime.universe.reify

println(reify{ myList.map(x => List(x, 2*x)).flatten }.tree)

you'll see

App.this.myList.map(((x) => `package`.List.apply(x, 2.$times(x)))).flatten(Predef.$conforms)

so implicit toIterableOnce: A => IterableOnce[B] is Predef.$conforms (you were right, it's in Predef)

https://github.com/scala/scala/blob/2.13.x/src/library/scala/Predef.scala#L510

/** An implicit of type `A => A` is available for all `A` because it can always
 *  be implemented using the identity function. This also means that an
 *  implicit of type `A => B` is always available when `A <: B`, because
 *  `(A => A) <: (A => B)`.
 */
// $ to avoid accidental shadowing (e.g. scala/bug#7788)
implicit def $conforms[A]: A => A = <:<.refl

Indeed, List[Int] <: IterableOnce[Int]

implicitly[List[Int] <:< IterableOnce[Int]] // compiles
implicitly[List[Int] => IterableOnce[Int]] // compiles

It's useful to know how to debug implicits:

In scala 2 or 3, is it possible to debug implicit resolution process in runtime?

CodePudding user response:

FWIW, if using Scala 2, you can also run your program with the -Xprint:typer flag using either scala or scalac, and you'll see all the implicits the compiler inserts in your program:

  println(myList.map(x => List(x, 2*x)).flatten)

Gets translated into:

scala.Predef.println(Main.this.myList.map[List[Int]](((x: Int) => 
  scala.`package`.List.apply[Int](x, 2.*(x))))
    .flatten[Any](scala.Predef.$conforms[List[Int]]))
  • Related