Can somebody explain why the following does not work. Somehow looses the compile some information for the type inference when i do toSet
, but i don't understand why.
scala> case class Foo(id: Int, name: String)
defined class Foo
scala> val ids = List(1,2,3)
ids: List[Int] = List(1, 2, 3)
scala> ids.toSet.map(Foo(_, "bar"))
<console>:11: error: missing parameter type for expanded function ((x$1) => Foo(x$1, "bar"))
ids.toSet.map(Foo(_, "bar"))
^
scala> ids.map(Foo(_, "bar")).toSet
res1: scala.collection.immutable.Set[Foo] = Set(Foo(1,bar), Foo(2,bar), Foo(3,bar))
Suppose I've got the following:
trait Pet {
def name: String
}
case class Dog(name: String) extends Pet
val someDogs: List[Dog] = List(Dog("Fido"), Dog("Rover"), Dog("Sam"))
Set
isn't covariant in its type parameter, but List
is. This means if I have a List[Dog]
I also have a List[Pet]
, but a Set[Dog]
is not a Set[Pet]
. For the sake of convenience, Scala allows you to upcast during a conversion from a List
(or other collection types) to a Set
by providing an explicit type parameter on toSet
. When you write val a = ids.toSet; a.map(...)
, this type parameter is inferred and you're fine. When you write ids.toSet.map(...)
, on the other hand, it's not inferred, and you're out of luck.
This allows the following to work:
scala> val twoPetSet: Set[Pet] = someDogs.toSet.take(2)
twoPetSet: Set[Pet] = Set(Dog(Fido), Dog(Rover))
While this doesn't:
scala> val allDogSet: Set[Dog] = someDogs.toSet
allDogSet: Set[Dog] = Set(Dog(Fido), Dog(Rover), Dog(Sam))
scala> val twoPetSet: Set[Pet] = allDogSet.take(2)
<console>:14: error: type mismatch;
found : scala.collection.immutable.Set[Dog]
required: Set[Pet]
Note: Dog <: Pet, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Pet`. (SLS 3.2.10)
val twoPetSet: Set[Pet] = allDogSet.take(2)
^
Is this worth the confusion? I don't know. But it kind of makes sense, and it's the decision the Collections API designers made for toSet
, so we're stuck with it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With