The teleological answer is that this is because contains
is defined in SeqLike
, but not in ParSeqLike
.
If this does not satisfy your curiosity, you may find that SeqLike
contains
is defined as follows:
def contains(elem: Any): Boolean = exists (_ == elem)
So for your example you can write
List.range(0,100).par.exists(_ == 2)
ParSeqLike
also lacks several other methods, some of which are difficult to implement efficiently (for example, indexOfSlice
), and some for less obvious reasons (for example, combinations
- perhaps because it is useful only for small data sets). But if you have a parallel collection, you can also use .seq
to return to the linear version and return your methods:
List.range(0,100).par.seq.contains(2)
As for why the library designers left this ... I fully guess, but maybe they wanted to reduce the number of methods for simplicity, and it is almost as easy to use exists
.
This also raises the question of why contains
is defined on SeqLike
and not on the grandfather of all collections, GenTraversableOnce
, where do you find exists
? A possible reason is that contains
for Map
semantically different from the Set
and Seq
methods. A Map[A,B]
is Traversable[(A,B)]
, so if contains
were defined for Traversable
, contains
need to take a tuple (A,B)
; however, Map
contains
accepts only argument A
Given this, I think that contains
should be defined in GenSeqLike
- perhaps this is an oversight that will be fixed.
(At first I thought that parallel sequences do not have contains
, because searching where you are going to stop after finding your target in parallel collections is much less efficient than the linear version (various threads make a lot of unnecessary work after the value is found: see this question ), but it may not be right because there exists
.)