stefano casadei
stefano casadei

Reputation: 43

bound mismatch error in java generic method when using self-referring type

I am getting a bound mismatch error when using a self-referring type in a generic method, but not in a generic class declaration; here is an example of the faulty code:

public class Container {
   public static class User<X> {}  // line 1
   public static class Box<U extends User<Box<U>>> {} // line 2
   public static class NiceBox<U extends User<Box<U>>> {}   // line 3: OK
   <U extends User<Box<U>>> void niceMethod(U user) {}   // line 4: NOT OK
}

Compile error message on line 4: Bound mismatch: The type U is not a valid substitute for the bounded parameter < U extends Container.User<Container.Box<U>>> of the type Container.Box<U>

I don't understand why, thanks in advance for any help, SC

PS: Note that differently from previously asked questions, the problem presented here exists only with generic methods, the compiler accepts the problematic type bound when used within a generic class declaration.

I am using the compiler for Java 11 coming with the latest Eclipse distribution.

Here are more details on what I am trying to achieve. I am building a Box that needs to execute some work on a target of type T within a context of type C, where this context C must satisfy a minimal interface. Then I need to define methods to process a Box (hence the need for a generic method with the self-referring type bound). Here is the code:

static class Box<T,C extends MinimalContext<Box<T,C>>> {
    void doSomething(T target, C context) {
        // do something
    }
}

interface MinimalContext<B> {   
    boolean validate(B box);
    void print(B box);
}

// FAILS:
<T,C extends MinimalContext<Box<T,C>>>
void processBox(Box<T,C> box) {}   

// Instead use:
class BoxProcessor<T,C extends MinimalContext<Box<T,C>>>    
{
    BoxProcessor(Box<T,C> box) {
        // use box as niceMethod would do 
    }
}

Note that since the limitation exists only for generic method and not for classes, I am using an inner class to do the work of the generic method...any other solutions?

Could someone from the eclipse developers say more about this limitation?

Upvotes: 2

Views: 284

Answers (1)

Malcolm Smith
Malcolm Smith

Reputation: 3580

It seems this is either a limitation of, or higher level of strictness from the Eclipse compiler. javac accepts that code fine.

In Eclipse you could write:

public static class User<T> {}
public static class Box<T extends User<Box<T>>> {}
<T extends User<Box<?>>> void niceMethod(T user) {}

You can then declare a class:

static class UserBox extends User<Box<?>> {}

And Eclipse will allow you to:

public static void main(String[] args)
{
    Container c = new Container();

    c.niceMethod(new UserBox());
}

But then it won't let you create a concrete Box. E.g:

Box<UserBox> b = new Box<>();

Is not allowed by Eclipse, but is by javac.

I suspect Eclipse might be doing the right thing, because you are saying:

"Box takes a type parameter of a class that extends a User with a type parameter of a Box which has a type parameter of the type we are extending." Which sounds impossible to me, but there could be something I'm missing.

EDIT (since the question was updated to show the interface):

Rather than define the interface as completely generic and try to restrict the context types in the definition of Box could you instead define a more restrictive interface, such as:

interface BoxContext<B extends Box<?, ?>> {
    boolean validate(B box);
    void print(B box);
}

You can then remove the self-referential generics from your definition of Box:

static class Box<T, C extends BoxContext<?>> {
    void doSomething(T target, C context) {
        // do something
    }
}

Which then allows you to define your method:

<T, C extends BoxContext<?>> void processBox(Box<T, C> box) {}

Upvotes: 1

Related Questions