On Mon, Aug 5, 2013 at 9:00 PM, Vlad Patryshev
<vpatr...@gmail.com> wrote:
Comments welcome.
It only works because of type inference implementation details. Yes, this doesn't compile:
val xs = HeadWithTail(5, HeadWithTail(10, EmptyList))
println(xs contains "abc")
...but only because the type inferencer infers Int during the implicit conversion, then obstinately refuses to reconsider the situation. If it were more ambitious, it would find this:
println((xs: MyList[Any]) contains "abc")
which compiles fine. You don't want this inference detail to be the foundation of anything.
The problem is inherent in any attempt to graft contains onto a covariant collection. If contains is applicable to the covariant type, then no matter how you try to obscure it, the Foo[T] is a Foo[Any] and its contains takes an Any.
However...
I believe I've found a more robust way out, but it won't happen in the "real" collections. An unexpected bonus was the invariant List. It's really nice not seeing my list of 1000 Ints quietly turn into a list of AnyVals when the 1001th element is a Double. How could that be what I meant? Now it's a type error.
// APIs - pure interfaces - all covariant - none has a contains method.
trait Foreach[+A] {
def isEmpty: Boolean
def foreach(f: A => Unit): Unit
}
trait Iterable[+A] extends Foreach[A] {
def iterator: Iterator[A]
}
trait Mapping[-A, +B] {
def apply(x: A): B
}
trait Seq[+A] extends Iterable[A]
trait Set[+A] extends Iterable[A]
trait Map[K, +V] extends Set[K] with Mapping[K, V]
trait IntMapping[+B] extends Mapping[Int, B] {
trait Contains[A] {
def contains(x: A): Boolean
}
object Seq {
trait Linear[+A] extends Seq[A] {
def head: A
def tail: Linear[A]
}
trait Indexed[+A] extends Seq[A] with IntMapping[A] {
def size: Int
}
}
// Leaf nodes - all final, concrete, invariant - contains method introduced here.
// If you need covariance, weaken to Seq[+A] and all you lose is contains and
// any other last minute arrivals.
final class Range private (start: Int, end: Int, step: Int, val size: Int)
extends Seq.Indexed[Int] with Contains[Int] { ... }
sealed abstract class List[A] extends Seq.Linear[A] with Contains[A] { ... }
final case object Nil extends List[Any] { ... }
final case class ::[A](head: A, tail: List[A]) extends List[A] { ... }
// etc etc