Reputation: 1406
Suppose I want to implement some sort of immutable set in scala and I want it to have 2 methods -- add and contains. Also it seems logical to me that a Set[Cat]
is a set of Set[Animals]
(thus I want it to be declated as MySet[+A]
).
So I write something like this
class MySet[+A] {
def add[B >: A](elem: B): MySet[B]
}
Which seems to be ok until I try to implement contains
method. In my opinion, the best fitting signature for a method like it should be def contains(elem: A): Boolean
because a set of Cat
s can only contain Cat
s. It can not contain Dog
s or any other animals.
Of course scala complains about the method like this: Covariant type A occurs in a contravariant position in type A of value elem
and I even understand why.
My question is how to convince scala that my method contains
does not mutate my collection in any way and it is safe to pass an element of type A
into it.
Upvotes: 1
Views: 87
Reputation: 14217
If for typesafe contains
, you can try to create the typesafe implicits
for contains
to solve Set
's contains
method parameter must be cotravariant
problem, like:
//implicit bound for `MySet` with the type `A`, so in there `A` is invariant type.
implicit class TypeSafeMySetContains[A](s: MySet[A]) {
def has(a: A): Boolean = s.contains(a) // invoke the `contains` method check
}
MySet(1, 2, 3) has "3" // the compiler will throw type mismatch error
MySet(1, 2, 3) has 3
Upvotes: 1
Reputation: 40500
The problem is not that scala is afraid you are going to mutate the collection.
The problem is that, because your set is covariant, MySet[Cat]
is a subclass of MySet[Animal]
. So, if the latter is allowed to have def contains(a: Animal)
, the former must have one too.
You can make it work with the same trick you did with .add
:
def contains[B >: A](elem: B): Boolean
Note that the immutable Set
in standard scala library is actually invariant in the element type. That is because they wanted it to work as a function A => Boolean
, that would require it to have an apply(a: A)
that's essentially the same problem you are talking about.
And give back my nick BTW, this is not cool, man!
Upvotes: 2