Inheriting from a generic interface multiple times while respecting variance - java

I ran into a problem when trying to specialize a class that implements a generic interface where I wanted to inherit from the same interface as the super class, but with a more specific type argument. The following snippet shows a synthetic but complete example that cannot be compiled. The comment contains the error message from the Java compiler.
interface Producer<T> {
T get();
}
class NumberProducer implements Producer<Number> {
#Override
public Number get() { return null; }
}
// Producer cannot be inherited with different arguments: <java.lang.Integer> and <java.lang.Number>
class IntegerProducer extends NumberProducer implements Producer<Integer> {
#Override
public Integer get() { return null; }
}
In the PECS sense, Producer<T> is a producer, so Producer<Integer> would be a subtype of Producer<Number>, but there's no way to declare that in the definition of Producer<T>. Java does not allow IntegerProducer to inherit from NumberProducer and Producer<Integer> at the same time as IntegerProducer would then inherit from Producer<Integer> and Producer<Number> at the same time.
Is there a standard approach to this limitation, e.g. a pattern that solves the same problem without requiring this kind of inheritance?

Just add a parameter to the super class:
interface Producer<T> {
T get();
}
class NumberProducer<T extends Number> implements Producer<T> {
#Override
public T get() { return null; }
}
class IntegerProducer extends NumberProducer<Integer> { // Implicit: implements Producer<Integer>
#Override
public Integer get() { return null; }
}

Say we had a simple Method gimme.
public static <T> T gimme(Producer<T> p) { return p.get(); }
Within the context of gimme nothing is known about T. It could be Number, Integer or any other reference type. So, due to erasure, the compiler emits an interface call to Producer.get()Object rather than the specific call to, say, IntegerProducer.get()Integer. All types that implement Producer<T> with T != Object also implicitly implement Producer.get()Object. This implicit implementation forwards to the specific implementation. That might be NumberProducer.get()Number or IntegerProducer.get()Integer, but not both. That's why you can't implement the same interface twice.
Other languages allow this via definition site variance, where Producer<Integer> is a subtype of Producer<Number>, but alas, Java does not. The common workaround is to make NumberProducer generic as well.

If you want to ensure that T is of a specific subtype you can use
interface Producer<T extends Number>
Not sure what Producer reall is so I have to guess.
Update:
If I understand you correct then I would say, you need to declare an interface which is a Producer. That's simple.
From this interface i would derive a new interface with the respecitve base type.
i.e.:
interface Producer
{
base functions
};
interface Newproducer<T extends Producer>
{
};
Is this what you had in mind?

Related

How to ensure this is the generic type referenced in my class signature?

Suppose we have three classes - AbstractMessage, AbstractEngine, and AbstractAction. These three classes all reference each other in a generic fashion so each Engine has a corresponding message and action and you can refer to them directly in the code.
public class MyMessage<M extends AbstractMessage<M,E,A>, E extends AbstractEngine<M,E,A>, A extends AbstractAction<M,E,A>> {
This is working fine, but when I attempt to enforce behavior at the highest level I run into some problems. My AbstractAction class has an applyTo method defined thusly:
protected abstract M applyTo(E engine, Object guarantee);
and my AbstractEngine class has this
private final M apply(A action) {
return action.apply(this, this.guarantee);
}
And it is on this line that it balks - complaining that:
The method applyTo(E, Object) in the type AbstractAction<M,E,A> is not
applicable for the arguments (AbstractEngine<M,E,A>, Object)
Now the reason for this is clear - the E in question might be some OTHER AbstractEngine and there's no way to know if the subclass we're calling this from is actually an E.
My question is, how can I say for certainty that if you're going to class MyEngine extends AbstractEngine<M...,E...,A...> that MyEngine is MUST be an E? And to have this certainty baked into AbstractEngine?
Here is a small example that illustrates the problem.
class EngineExample {
static abstract class AbEng<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
final M func(A act) {
return act.apply(this); // compile error here
}
}
static abstract class AbMes<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
}
static abstract class AbAct<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
abstract void apply(E e);
}
static class RealEng extends AbEng<RealAct, RealMes, RealEng> {
}
static class RealMes extends AbMes<RealAct, RealMes, RealEng> {
}
static class RealAct extends AbAct<RealAct, RealMes, RealEng> {
void apply(RealEng eng) {
System.out.println("applied!");
}
}
}
Use loosest valid parameter type
The simplest solution, is to not actually enforce that this isInstanceOf E. The rules of abstraction already guarantee that this is a safe operation, so it will just work if you change the parameter to just allow any Engine.
abstract Action<E> {
public void apply(Engine<?> e, Object o) {
e.doSomething(o);
}
}
or
abstract Action<E> {
<T extends Engine<?>> public T apply(T e, Object o) {
return e.doSomething(o);
}
}
Use a type-safe wrapper
Another solution is to create another class that binds these 3 together, and move the interaction calls to the wrapper.
abstract System<A extends Action, M extends Message, E extends Engine> {
abstract void apply(A action, E engine) {
engine.render(action.apply())
}
}
Or have the wrapper class take an instance of these 3 and use the passed in versions. This basically is the "allow anything close enough" solution, and adding another class to manage how they can and can't talk to each other.
Pre-cast check
You can also make a reference cast on construction to throw an error if the cast setup is invalid.
private final E dis = (E) this;
This really just moves the problem from from always on compile time, to sometimes on run time, so in general, not a safe/stable solution.
This next solution is a bit specific to your case (using info from our discussion). Basically, you want to define a method in an abstract class that class A and B can inherit, but A and B should not be interchangeable using their base class.
Just use polymophism and use generics just as a type segregator
Here is a modification of the MVCe that uses polymorphism instead, using generics only as a kind of type-category-exclusive-locking mechanism. Basically, Type is a semantic interface to say whether semantically, it makes sense for these classes to talk to each other. (A Physics Engine and Light Engine may share some functionality, but it would make no sense to let them be interchangeable.)
class test {
public static void main(String[] rawrs) {
RealEng re = new RealEng();
RealAct ra = new RealAct();
MockAct ma = new MockAct();
ra.apply(re);
// Remove all code related to Type interface if next line should compile
ma.apply(re); // compile error here
}
static interface Type {
}
static interface Real extends Type {
};
static interface Mock extends Type {
};
static abstract class AbEng<T extends Type> {
final void func(AbAct<T> act) {
act.apply(this); // compile error here
}
}
static abstract class AbMes<T extends Type> {
}
static abstract class AbAct<T extends Type> {
abstract void apply(AbEng<T> e);
}
static class RealEng extends AbEng<Real> {
}
static class RealMes extends AbMes<Real> {
}
static class RealAct extends AbAct<Real> {
#Override
void apply(AbEng<Real> eng) {
System.out.println("applied!");
}
}
static class MockAct extends AbAct<Mock> {
#Override
void apply(AbEng<Mock> eng) {
System.out.println("applied!");
}
}
}
Recursive type-parameters in Java generics are often troublesome.
The problem here is that paradoxically there in no way that you can guaranteed that this makes reference to an instance of E; the only thing that we known about this is that it also extends Engine<M, A, E> but not that is actually E.
Obvious solution is to add a cast ((E)this) and that might be an acceptable solution but you must make clear in the contract (thru javadoc or other documentations) that Engine extending classes must assign E to themselves.
Another solution simply change those method signatures to be a bit more flexible and instead E accept any engine that extends Engine<M, A, E>.
protected abstract M applyTo(AbstractEngine<M, A, E> engine, Object guarantee);
Also consider to reduce the number of type-parameters whenever possible. For example does Engine need to make reference to its own type? Does it have any method that accepts or returns and engine that must be of the same type/class?
EDIT
If you want to keep the E type parameter in applyTo another option is to create a field typed E in AbstractEngine that would be the one passed to the apply to. This field in fact would make reference to this but once it has been "casted" safely at construction.:
public class AbstractEngine<M extends ..., A extends ..., E extends ...> {
private final E engine;
protected AbstractEngine(final E engine) {
this.engine = Objects.requiresNonNull(engine);
}
}
public class MyEngine extends AbstractEngine<MyMessage, MyAction, MyEngine> {
public MyEngine() {
super(this);
}
}
The reason this works is that when we are declaring MyEngine then the compiler does know that MyEngine is E and so the "cast" is safe one. Then the code in AbstractEngine can use the casted value safely thereafter.
The obvious inconvenience is the extra field making reference to this, that although is a bit of memory waste in practice is probably negligible.
Here we are adding the possibility that an engine could designate a surrogate engine to be used in their apply method calls. Perhaps that might be useful... but if you really want to make it impossible to use a third engine here, then you can change the code in the AbstractEngine constructor to compare the passed engine with this and fail at runtime if they are not the same.
protected AbstractEngine(final E engine) {
if (engine != this) {
throw new IllegalArgumentException();
}
this.engine = engine;
}
Unfortunately this cannot be check at compilation time... the second best thing you can do is to make it part of your code tests to verify that all AbstractEngine extending classes are compliant so it would fail at build-time.

overload method with same generic parameter?

I know that I can't do this:
public abstract class DTODomainTransformer<T, S> {
public abstract S transform(T);
public abstract T transform(S);
}
Because I get the compiler complaint:
Method transform(T) has the same erasure transform(Object) as another method in type Transformer<T,S>
I understand that is because both T and S could be extending same class. So doing this way i can tell him "No, they are not the same, so take it easy"
public interface Transformer<T extends AbstractDTO , S extends AbstractDomain> {
public abstract S transform(T object);
public abstract T transform(S object);
}
Then, my question is, is there any way to tell the compiler that T and S extend from different classes without telling which ones in concrete? I mean, in this last case, I've specified which classes had to be T and S (extending respectively). But what if I want it more generic and not specify them? I'd like to tell the compiler, "Hey, compiler, T and S are not the same! They are different classes. I don't know exactly which classes they are, but I'm sure that they are different".
There's not an obvious way. (Although you can build one, as I show below.)
This overload rule is due to a limitation of how the supertype (in this case, interface) that declares the overloads gets translated (by erasure) to bytecode.
If there's a generic parameter declared T, a method that uses T in its signature will have bytecode generated as the upper bound of T, for example
class Generic<T> {
void work(T t) {}
}
will get erased to
class Generic {
void work(Object t) {}
}
and
class Generic<T extends Number> {
void work(T t) {}
}
will get erased to
class Generic {
void work(Number t) {}
}
This is how the bounded example works, because the overloads erase differently.
public interface Transformer {
public abstract AbstractDomain transform(AbstractDTO object);
public abstract AbstractDTO transform(AbstractDomain object);
}
But without specific bounds, what erased bytecode should be generated for the overloaded methods?
So your T and S being different on the subtype is not what's important. What is important is the known declared bounds which get translated to erased bytecode for the supertype class.
A possible solution could use marker interfaces.
interface TransformT {}
interface TransformS {}
interface Transformable extends TransformT, TransformS {}
interface Transformer<T extends TransformT, S extends TransformS>
T transform(S s);
S transform(T t);
}
abstract class AbstractDTO implements Transformable {}
abstract class AbstractDomain implements Transformable {}
new SomeTransformerImpl<AbstractDTO, AbstractDomain>()
But I don't necessarily recommend doing this. It seems elaborate to me, although interesting. It depends on how complicated the actual class hierarchy is.
What Louis suggested in the comments is much simpler: give the methods different names.

generic interface: list of something specific

I want to define an interface MyList which is a list of interface MyThing. Part of the semantics of MyList is that its operations don't have any meaning on objects which do not implement the MyThing interface.
Is this the right declaration?
interface MyList<E extends MyThing> extends List<E> { ... }
edit: (part 2) Now I have another interface that returns a MyList as one of its methods.
// I'm defining this interface
// it looks like it needs a wildcard or template parameter
interface MyPlace {
MyList getThings();
}
// A sample implementation of this interface
class SpecificPlace<E extends MyThing> implements MyPlace {
MyList<E> getThings();
}
// maybe someone else wants to do the following
// it's a class that is specific to a MyNeatThing which is
// a subclass of MyThing
class SuperNeatoPlace<E extends MyNeatThing> implements MyPlace {
MyList<E> getThings();
// problem?
// this E makes the getThings() signature different, doesn't it?
}
Yes, at least that is how EnumSet does it.
public abstract class EnumSet<E extends Enum<E>>
extends AbstractSet<E>
Edit in answer to Part 2:
I'm not sure why the return type of getThings() in the interface doesn't complain about raw types. I suspect that because of type erasure, warnings in interfaces would be useless even if they were there (there's no warning if you change the return type to List, either).
For the second question, since MyNeatThing extends MyThing, E is within its bounds. That's sort of the point of using the extends bound in the generic parameter, isn't it?
For part 1, yes that looks right.
For your part 2, I suggest something like the following. The method returns a MyList of something, which you don't know what it is (it is different for different implementations apparently), but you know it's a subtype of MyThing.
interface MyPlace {
MyList<? extends MyThing> getThings();
}
Keep in mind that implementing interfaces like java.util.List correctly is hard; so ask yourself all of these questions:
Can I use java.util.List "as is", do
I need to add/remove functionality?
Is there something simpler I could implement, like Iterable<T>?
Can I use composition? (vs. inheritance)
Can I find the
newly desired functionality in
existing libraries like Google
Collections?
If I need to
add/remove functionality, is it worth
the added complexity?
That said, you could probably just use java.util.List for your example:
interface MyPlace<T extends MyThing> {
List<T> getThings();
}
class SpecificPlace implements MyPlace<MyThing> {
public List<MyThing> getThings() { return null; }
}
class SuperNeatoPlace implements MyPlace<MyNeatThing> {
public List<MyNeatThing> getThings() { return null; }
}

Is it possible to write a method that returns a class object of T?

If I have a base class such that
public abstract class XMLSubscription <T extends XMLMessage>
Is it possible to write a method in XMLSubscription that returns a class object of T?
The only possible solution that I came up with is to have each descendant of XMLSubscription have a method like:
public class XMLStatusSubscription extends XMLSubscription<XMLStatusMessage>
{
public Class <XMLStatusMessage> getExpectedMessageType()
{
return XMLStatusMessage.class;
}
}
Unfortunately - and yes, this is due to type erasure - there is no way to return the Class object without providing it at runtime somehow.
Fortunately this is not usually too difficult. Here's how I've typically done this / seen it done:
public abstract class XMLSubscription <T extends XMLMessage> {
private Class<T> messageType;
protected XMLSubscription(Class<T> messageType) {
this.messageType = messageType;
}
public Class<T> getExpectedMessageType() {
return this.messageType;
}
}
public class XMLStatusSubscription extends XMLSubscription<XMLStatusMessage> {
public XMLStatusSubscription() {
super(XMLStatusMessage.class);
}
}
As you guessed, T is erased by the compiler. When you instantiate the object it has no idea that's it's supposed to deal with XMLStatusMessage objects. Your base class would define the following template method, and 1.5's covariant return types would keep the compiler happy with the concrete subclasses:
public Class<T> getExpectedMessageType()
There is one meta-comment: this looks a lot like procedural code, where something calls getExpectedMessageType() and then takes action based on the return type. This might be better implemented using a Visitor pattern, with the visitor implementing "doSomething" methods for each of the subclasses of XMLMessage.

Overriding a method with Generic Parameters in Java?

I have an abstract Class Monitor.java which is subclassed by a Class EmailMonitor.java.
The method:
public abstract List<? extends MonitorAccount> performMonitor(List<? extends MonitorAccount> accounts)
is defined in Monitor.java and must be overridden in EmailMonitor.java.
I currently have the method overridden in EmailMonitor.java as follows:
#Override
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
//...unrelated logic
return emailAccounts;
}
However, this produces the compile time error:
Name clash: The method performMonitor(List<EmailAccount>) of type EmailMonitor has the same erasure as performMonitor(Lis<? extends MonitorAccount> emailAccounts) of type Monitor but does not override it
EmailAccount is a subclass of MonitorAccount, so (in my mind at least) overriding it in this way makes perfect sense. Seeing as the compiler is not happy with my logic though, How should I go about this correctly while still keeping my compile time checks to make sure that all calls to EmailMonitor.performMonitor() receive Lists of EmailAccount rather than some other type of MonitorAccount?
No, it's not overriding it properly. Overriding means you should be able to cope with any valid input to the base class. Consider what would happen if a client did this:
Monitor x = new EmailMonitor();
List<NonEmailAccount> nonEmailAccounts = ...;
x.performMonitor(nonEmailAccounts);
There's nothing in there which should give a compile-time error given your description - but it's clearly wrong.
It sounds to me like Monitor should be generic in the type of account it can monitor, so your EmailMonitor should extend Monitor<EmailAccount>. So:
public abtract class Monitor<T extends MonitorAccount>
{
...
public abstract List<? extends T> performMonitor(
List<? extends T> accounts);
}
public class EmailMonitor extends Monitor<EmailAccount>
{
#Override
public abstract List<? extends EmailAccount> performMonitor(
List<? extends EmailAccount> accounts)
{
// Code goes here
}
}
You might want to think carefully about the generics in the performMonitor call though - what's the return value meant to signify?
Here is my own solution. I suspect this is the same thing Jon Skeet was trying to get at... without the typo (see my comment in reply to his answer).
the Monitor.java class:
public abstract class Monitor <T extends MonitorAccount> {
...
public abstract List<T> performMonitor(List<T> accounts);
..
}
EmailMonitor.java
public class EmailMonitor extends Monitor<EmailAccount> {
...
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
..//logic...logic...logic
return emailAccounts;
}
...
}
In this configuration, EmailMonitor.performMonitor() will always check at compile time that it receives a list of EmailAccount rather than any of my other types FTPAccount, DBAccount, etc... It's much cleaner than the alternative, which would have been receiving/sending a raw list and then having to coerce it the required type resulting in potential runtime type casting exceptions.

Categories