Why does converting a Seq to a Set and then calling map on same line not compile

Viewed 54

Say I define the following code:

val x: Seq[String] = Seq()
val y = x.toSet.map(s => (s, true))

This will not compile, giving me a missing parameter type error.

But if I break it down thus:

val x: Seq[String] = Seq()
val y = x.toSet
val z = y.map(s => (s, true))

it compiles fine. Why is this?

1 Answers

Note how there are multiple choices for which types fit

x.toSet[Any].map[(Any, Boolean]]((s: Any) => (s, true))
x.toSet[AnyRef].map[(AnyRef, Boolean]]((s: AnyRef) => (s, true))
x.toSet[String].map[(String, Boolean]]((s: String) => (s, true))

and as Rex explains Scala 2 should

...pick the most specific value. But since functions are contravariant in their argument, they are most specific when they take an Any as an argument, so the compiler can't decide.

For example consider how because of argument contravariance function Any => _ is more specific than String => _

implicitly[(Any => _) <:< (String => _)]   // ok

Inferring Any is never ideal so compiler asks the programmer for explicit help.

Now Scala 3 seems to have implemented Rex's suggestion

There could exist a rule to break the tie ("prefer the early assumption"), but there isn't one implemented.

which makes it compile

scala> Seq.empty[String].toSet.map(s => (s, true))
val res0: Set[(String, Boolean)] = Set()
Related