Why this code doesn’t work:
scala> List('a', 'b', 'c').toSet.subsets.foreach(e => println(e))
<console>:8: error: missing parameter type
List('a', 'b', 'c').toSet.subsets.foreach(e => println(e))
^
But when I split it then it works fine:
scala> val itr=List('a', 'b', 'c').toSet.subsets
itr: Iterator[scala.collection.immutable.Set[Char]] = non-empty iterator
scala> itr.foreach(e => println(e))
Set()
Set(a)
Set(b)
Set(c)
Set(a, b)
Set(a, c)
Set(b, c)
Set(a, b, c)
And this code is OK as well:
Set('a', 'b', 'c').subsets.foreach(e => println(e))
First, there’s a simpler version of the code that has the same issue:
This doesn’t work either
However, these work just fine:
If you go take a look at the
Listclass documentation you’ll see that the methods that work return some type parameterized withA, whereas methods that don’t work return types parameterized withB >: A. The problem is that the Scala compiler can’t figure out whichBto use! That means it will work if you tell it the type:Now as for why
toSetandtoBufferhave that signature, I have no idea…Lastly, not sure if this is helpful, but this works too:
Update: After poking around the docs a little bit more I noticed that the method works on all the types with a covariant type parameter, but the ones with an invariant type parameter have the
B >: Ain the return type. Interestingly, althoughArrayis invariant in Scala they provide two version of the method (one withAand one withB >: A), which is why it doesn’t have that error.I also never really answered why breaking the expression into two lines works. When you simply call
toSeton its own, the compiler will automatically inferAasBin the type for the resultingSet[B], unless you do give it a specific type to pick. This is just how the type inference algorithm works. However, when you throw another unknown type into the mix (i.e. the type ofein your lambda) then the inference algorithm chokes and dies—it just can’t handle an unknownB >: Aand an unknown type ofeas well.