Why does Iterator have a contains method but Iterable does not, in Scala 2.8?
Asked Answered
B

2

16

I would like to call 'contains' on my Iterables :-)

Brython answered 27/5, 2010 at 23:37 Comment(0)
G
28

The reason Iterable does not have a contains method is because the way it is defined can have direct consequences on variance. Basically, there are two type signatures that make sense for it:

def contains(v: Any): Boolean
def contains(v: A): Boolean

The second definition has increased type safety. However, A, which is the type parameter of collection, appears in a contra-variant position, which forces the collection to be invariant. It could be defined like this:

def contains[B >: A](v: B): Boolean

but that wouldn't offer any improvement over the first signature, using Any.

As a consequence of this, you'll see that immutable.Seq is co-variant and uses the first signature, while immutable.Set is invariant and uses the second signature.

Gorky answered 13/7, 2010 at 1:58 Comment(3)
Note: contains is implemented using the signature contains[A1 >: A](elem: A1) in SeqLike (at least in Scala 2.11.8). I do not think this is the same as using Any - it places some constraints on the B type - you can pass Any, but you cannot pass a type which is known to be unrelated.Tend
@Tend Sure you can. Go ahead and try. If you pass an unrelated type, A1 will be inferred to be the common supertype. And because everything is descendant from Any, then all types have a common supertype with each other.Gorky
You are right. Is there any reason why is the signature in the library as it is, and not with Any, as you write, then?Tend
E
5

I don't know why contains is not defined on Iterable or TraversableOnce, but you could easily define it yourself:

class TraversableWithContains[A](underlying: TraversableOnce[A]) {
  def contains(v: Any): Boolean =
    underlying.exists(_ == v)
}
implicit def addContains[A](i: Iterable[A]) = new TraversableWithContains(i)

and use it as if it were defined on Iterable:

val iterable: Iterable[Int] = 1 to 4
assert(iterable.contains(3))
assert(!iterable.contains(5))
Embowel answered 12/7, 2010 at 16:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.