mon mon - 3 months ago 41
Scala Question

Acceptable parameter combinations for flatten method

Question



Would like to understand the cause of the error and meaning of the error messages. Initially thought it was because of mixing String and Character, but mixing String and Integer was possible.

Problem



Expected below would produce List(tako, saba, ika, h, a, m, a, c, h, i) like List(tako, saba, ika, 1, 2, 3) mixing string and integer. However it caused errors.

println(
List(
List("tako", "saba", "ika"),
"hamachi"
).flatten)
^^^^^^^^
No implicit view available from java.io.Serializable => scala.collection.GenTraversableOnce[B].
not enough arguments for method flatten: (implicit asTraversable: java.io.Serializable => scala.collection.GenTraversableOnce[B])List[B]. Unspecified value parameter asTraversable.


Below worked.

println(
List(
"hamachi"
).flatten)
----
List(h, a, m, a, c, h, i)

println(
List(
List("tako", "saba", "ika")
).flatten)
----
List(tako, saba, ika)

println(
List(
List("tako", "saba", "ika"),
List(1,2,3)
).flatten)
----
List(tako, saba, ika, 1, 2, 3)

Answer

The signature of flatten is

def flatten[B](implicit asTraversable: A => GenTraversableOnce[B]): CC[B]

You can check out more about this in the source. So, about the error you get: when you make List(List("tako", "saba", "ika"), "hamachi"), scala has to infer the generic type of the List you are making. The way it does this is that it takes the least common ancestor of all the types in the list. In this case, it so happens that the closest class/trait that List("tako", "saba", "aka"): List[String] and "hamachi: String" share is java.io.Serializable.

Now, scala has to look for an implicit parameter asTraversable: A => GenTraversableOnce[B], but it doesn't find one. Since it already figured out that A = java.io.Serializable, it gives you as helpful an error message as it can muster: it didn't find any implicit of type java.io.Serializable => scala.collection.GenTraversableOnce[B] to give to asTraversable.


Now, what about the other calls? Where are they getting their implicits? Mostly from the Predef I think. This IMO is one of Scala's weaknesses - noticing, tracing, and debugging implicits. They are absolutely lovely until you try something that requires some complex implicit no one thought of defining. Oh well, no such thing as a free lunch.

Comments