Missing parameter type error by calling toSet

Why this code does not 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 break it, 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 fine:

 Set('a', 'b', 'c').subsets.foreach(e => println(e)) 
+6
scala
source share
1 answer

Firstly, there is a simpler version of the code that has the same problem:

 List('a', 'b', 'c').toSet.foreach(e => println(e)) 

This does not work.

 List('a', 'b', 'c').toBuffer.foreach(e => println(e)) 

However, these works are simply wonderful:

 List('a', 'b', 'c').toList.foreach(e => println(e)) List('a', 'b', 'c').toSeq.foreach(e => println(e)) List('a', 'b', 'c').toArray.foreach(e => println(e)) 

If you look at the List documentation for the class , you will see that the methods that work return a type parameterized with A , while the methods that don't work return the types parameterized with B >: A The problem is that the Scala compiler cannot determine which B use! This means that it will work if you specify the type:

 List('a', 'b', 'c').toSet[Char].foreach(e => println(e)) 

Now, why toSet and toBuffer have this signature, I have no idea ...

Finally, not sure if this is useful, but this also works:

 // I think this works because println can take type Any List('a', 'b', 'c').toSet.foreach(println) 

Update: After I looked into the documents several times, I noticed that this method works in all types with a covariance type parameter, but those that have an invariant type parameter have B >: A in the returned type. Interestingly, although Array is invariant in Scala, they provide two versions of the method (one with A and one with B >: A ), so it does not have this error.

I also never answered why splitting an expression into two lines works. When you simply call toSet yourself, the compiler automatically outputs A as B to the type for the resulting Set[B] , unless you let it choose a specific type. This is how the type inference algorithm works. However, when you inject another unknown type into the mix (i.e., Type e in your lambda), the output algorithm throttles and dies - it simply cannot process the unknown B >: A and unknown type e as well.

+6
source share

All Articles