I have an Either<L, R>
class, which represents a value of one of two types, or semantically different states. In some cases, it is valuable to operate on it no matter which alternative the value is.
I want a (non-static) method that takes a Consumer<T>
, where T
is a supertype of both L
and R
, where L
and R
are type parameters for the class.
Currently, java lets me do this: (static implementation)
public static <T, L extends T, R extends T> void collapse(Either<L,R> e, Consumer<T> op)
But of course, with a non-static implementation, I can't impose constraints on L
and R
, because they're already defined for the instance in question. I need those constraints imposed on T
instead, but java won't let me write the following because it only allows one class in a supertype or subtype constraint at once. This is especially frustrating given all classes share at least Object
as a common supertype, so these constraints are always satisfiable.
public void collapse(Consumer<? super L & R> op)
Is there any other way to define this constraint, any hint of it being allowed in a later version of java, or any explanation of why it would be a breaking feature?
In your static version, since you need the consumer to be able to accept either the "L" or the "R" type, you don't actually need those type variables: Either<? extends T, ? extends T> e
.
But beyond this, I would say that your static version is really the best you can do. Java just doesn't have a particularly expressive type system.
I don't think that Eran's answer is a particularly good solution (with respect), because:
Object
(which is annoyingly broad), you'll always find a case where you wish it were just a tiny bit more permissive;Either
type, even where you don't need to use the consumer, because you have to always provide 3 type parameters (even if they are ?
). A third type parameter just feels like cruft.The only real downside I see to the static version is the slightly awkward calling convention: Either.collapse(anEither, aConsumer)
as opposed to anEither.collapse(aConsumer)
. Sure, the former is marginally more verbose... but it does what you want, so you may just have to accept the awkwardness.
Perhaps you should add T
as a third type parameter of your class:
class Either<T, L extends T, R extends T>
{
public void collapse(Consumer<T> op) {
}
}
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