4

So given the list:

val a:List[Int] = List(1,2,3)

You can do:

a.contains(Option(2))

Which returns false. I understand from the following function definitions that allowing this to compile at all was done on purpose:

def contains[A1 >: A](elem : A1) : scala.Boolean = {...}
sealed abstract class Option[+A]() ...

What I don't understand is why - is there a use case where this is useful? If it automatically flattened the option before the comparison so the above returned true then it might be useful but as is it will always return false.

I ask because it's easy to forget to unwrap your Option variable that you pass to List.contains, leading to potentially difficult to find bugs.

Thanks!

JBY
  • 238
  • 2
  • 10
  • 1
    As has been pointed out, `contains()` takes any arg type. To retain type safety we can use `exists()`. – jwvh Jul 17 '15 at 03:19
  • Thanks all, just to summarize for others - the following 2 options exist for retaining type safety (ie. both fail to compile): `a.contains[Int](Option(2))` and `a.exists(_==Option(2))` – JBY Jul 17 '15 at 17:48

1 Answers1

4

Imagine the following:

sealed trait Result
case class SimpleResult(x: Int) extends Result
case class FancyResult(x: Int, y: Int) extends Result

val okResults: List[SimpleResult] = // ...

def calcResult: Result = ???

okResults.contains(calcResult)

This is a case where it is useful that you can call contains with a supertype of the type of the List.

In your case, a nasty side-effect happens: Option[Int] is not a supertype of Int. However, they have a common supertype: Any. So your call to contains gets inferred to:

a.contains[Any](Option(2))

Since Option[Int] is a subtype of Any, you are allowed to pass it to contains. This is probably something you wouldn't want in most cases, but it is hard (impossible?) to define such an interface in Scala's type system.

gzm0
  • 14,752
  • 1
  • 36
  • 64
  • 1
    Option[Int] is not a supertype of Int though – Cubic Jul 17 '15 at 00:45
  • Yes. But `Any` is a supertype of `Int` and `Option[Int]` is a subtype of `Any`, therefore you may pass it to a method that takes an `Any`. Please remove downvotes. Being able to pass `Option[Int]` is a direct consequence from subtyping and `A1` being unbounded (since there is no sensible upper bound). – gzm0 Jul 17 '15 at 01:57
  • "but it is hard (impossible?) to define a type system with subtyping that prevents you from doing this" You could have a system with subtyping but without a top type like `Any`. – Alexey Romanov Jul 17 '15 at 07:34
  • @AlexeyRomanov hahaha, I knew someone will give me a solution. While your proposal sounds unpractical at first, it is actually something I think is **very** reasonable and I often reason and write code like that. Do you have a way I could formulate that in the answer without making a too bold statement? – gzm0 Jul 17 '15 at 17:34
  • C++ is an example of such a type system :) – Alexey Romanov Jul 17 '15 at 18:16
  • Amazing... Why has this never occurred to me :) – gzm0 Jul 17 '15 at 18:23