I have 3 traits
trait A
trait B
trait AB extends A with B
and a method
def collect[E: Manifest](list: List[Any]) =
list flatMap {
case record: E => Some(record)
case _ => None
}
For the given list
val list = new A {} :: new A {} :: new A with B {} :: new AB {} :: Nil
I invoked collect
with different types
collect[A with B](list) // collect all elements from the list
collect[AB](list) // collect only the last element
Could anyone explain the difference in behavior for A with B
and AB
types?
It is highly unintuitive but it conforms to the specification. First, quoting from the Manifest docs (emphasis mine):
A Manifest[T] is an opaque descriptor for type T. Its supported use is to give access to the erasure of the type
So in collect[A with B]
we are matching the erasure of A with B
. And what is that? if we look at the Type erasure section of the spec, we read:
The erasure of a compound type T1 with ... with Tn is the erasure of the intersection dominator of T1, ..., Tn
and the intersection dominator is defined as (again, emphasis mine)
The intersection dominator of a list of types T1, ..., Tn is computed as follows. Let Ti1, ..., Tim be the subsequence of types Ti which are not supertypes of some other type Tj. If this subsequence contains a type designator Tc that refers to a class which is not a trait, the intersection dominator is Tc. Otherwise, the intersection dominator is the first element of the subsequence, Ti1
In our case the subsequence is A,B
as they don't have any subtyping relationship, and thus the erasure of A with B
is A
, so that in collect[A with B]
we are actually matching A
.
You can easily see this behavior by looking at the output of collect[B with A]
, and/or adding a new B {}
to your list
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With