It occurs to me that the use cases of both eliminating a type from a union, and eliminating a type from an intersection, could be solved by introducing a “not” mechanism for types. Imagine for example there was a syntax ~X
which had the meaning of “The union of all types besides X
”. Then you could express the OP’s use case kinda like this:
trait Either[+A, +B] {
def recoverOn[E, BB >: B](fn: E => B): Either[A & ~E, BB] = ???
}
where A & ~E
eliminates E
from the union type A
(if it is present).
Similarly, the use case for removing a type from an intersection (I won’t go into the reasons but I’ll clarify that in the use case I had, the intersection type is a phantom type), given an intersection type X
like A & B & C
, you could use a type bound XX >: X <: ~B
for example to infer the type which is the narrowest supertype of X
which is disjoint with B
(i.e. A & C
).
I guess it’s a little late to propose something like that for dotty, but it would be pretty powerful!