Unexpected behavior with compound types

I have 3 traits

trait A trait B trait AB extends A with B 

and method

 def collect[E: Manifest](list: List[Any]) = list flatMap { case record: E => Some(record) case _ => None } 

For this list

 val list = new A {} :: new A {} :: new A with B {} :: new AB {} :: Nil 

I called collect with different types

 collect[A with B](list) // collect all elements from the list collect[AB](list) // collect only the last element 

Can someone explain the difference in behavior for types A with B and AB ?

+6
source share
1 answer

This is very unintuitive, but meets specifications. First, quoting Manifest docs (my attention):

The manifest [T] is an opaque type descriptor T. Its supported use is access to type erasure

So, in collect[A with B] we compare the erasure of A with B And what is it? if we look at the type of erasure in the specification, we read:

Erasing a composite type T1 with ... with Tn is an erasing of the dominance of the intersection T1, ..., Tn

and the intersection dominant is defined as (again, my emphasis)

The intersection surface of the list of types T1, ..., Tn is calculated as follows. Let Ti1, ..., Tim be a subsequence of types Ti that are not supertypes of some other type Tj. If this subsequence contains a designation of type Tc, which belongs to a class that is not a sign, then the intersection dominant is Tc. Otherwise, the dominant intersection element is the first element of the subsequence, Ti1

In our case, the subsequence A,B , because they do not have a subtyping relationship, and therefore erasing A with B is equal to A , so in collect[A with B] we actually match A

You can easily see this behavior by looking at the output of collect[B with A] and / or adding new B {} to your list .

+5
source

Source: https://habr.com/ru/post/1013382/


All Articles