3

I have a class which has a self referential generic parameter and a parameter which is of the same super class. The static function has identical bounds as the class.

public class Bar<T extends Bar<T, C>, C extends Bar<C, ?>> {

    Bar() {
        foo((T) null);
        foo((C) null);//compile error
    }

    static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ?>> void foo(S_T t) {
    }
}

This gives the following error.

Bound mismatch: The generic method foo(S_T) of type Bar<T,C> is not applicable for the arguments (C). The inferred type C is not a valid substitute for the bounded parameter <S_T extends Bar<S_T,S_C>>

I can't figure out why C can't be passed in to foo() since C is Bar<C,?> and the wildcard is a Bar because of the second parameter in the declaration says it extends Bar.

I know this is probably a bad idea and produces code which is hard to understand but I really wanna know why this doesn't compile.

2
  • possibly related to my question stackoverflow.com/questions/9937422/… Commented Jun 11, 2012 at 23:02
  • @JudgeMental somewhat similar; but from what I gathered from your question it's the class hierarchy that failed to compile, while my class hierarchy compiles but fails on the argument constraint for the function. Commented Jun 11, 2012 at 23:44

2 Answers 2

2

The short answer is that Java type inference is actually pretty lame.

Java is not performing any intelligent inference on the wildcard ? in the declaration of Bar to infer that it is logically bounded by Bar< ?, ? > (nor that the ?s in that bound are themselves bounded, and so on). Once you put ? by itself, that's all Java knows. Although nothing is stopping you from putting that bound in on the wildcard in the declaration of Bar, even that does not help Java; Java won't ever assume that two separate ?s refer to the same type, even if deeper analysis would imply that they have to be. In other words, the compile error persists even with this code:

public class Bar<T extends Bar<T, C>, C extends Bar<C, ? extends Bar<?, ? extends Bar<?, ?>>>> {

    Bar() {
        foo((T) null);
        foo((C) null);//compile error
    }

    static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ? extends Bar<?, ? extends Bar<?, ?>>>> void foo(S_T t) {
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Yes, I started to suspect that java couldn't detect the connection between the wildcard bounds. I started experimenting with supplying a class: Pie extends Bar<Pie,Pie> instead of the wildcard. Then the function would have <S_T extends Bar<S_T,S_C>, S_C extends Bar<S_C,Pie> and one could still have methods on Bar which would return S_C....But I might be completly off target now (almost 3am here)
what would be wrong with Bar< S_T, S_C > as the argument type to foo? The only information you can use about S_T in foo is that it is a Bar< S_T, S_C > anyway. Plus that makes foo (theoretically, at least) more general.
What would be the generic parameters for the function? Do you mean just defining S_T and S_C without any bounds, because then Bar<S_T,S_C> in the argument won't match the bounds for the Bar class
Right, that doesn't help much. It occurs to me that if you want to call foo( ( C )null ), you don't care about the second parameter to Bar in foo either, which means why not just static <S_T extends Bar<S_T, ?>> void foo( S_T t ) {} ?
Well that kinda works, depending of what one want to do, since you can't call new Bar<S_T,S_C>() if you have a wildcard instead of S_C.
0

I'm not a crack with generics, but I think the problem is that you declare the type of foo() to be

<S_T extends Bar<S_T,S_C> > void foo(S_T)

and then call it in two different contexts that require a different static type for foo().

In the fist context S_T has type T and in the second context it has type C. But T and C are declared as Bar<T,?> and Bar<C,?>, which are incompatible types statically. I would guess that the compiler figures out the type of foo() in the first call and then assumes correctly, that the type must remain the same throughout, which it doesn't.

3 Comments

Switching the order of the two foo() calls still gives an error on the line with the C.
OK, try changing the order of C and T in the class declaration, ie. do Bar<C extends Bar<C,T>, T extends Bar<T,?>. If the error flips then, it means that the type bindings also depend on the order of the types in the class declaration. But in either case, C and T have different incompatible types and you can't pass both into foo().
I tried the change you suggested and the error changed to T but I think that's simply because all it did was rename the parameters, not change any meaning. I tried a couple of different ways of reording the parameters and the error stays on the parameter which has the wildcard. Also I think that although C and T are incompatible with eachother both should be compatible with the static function since AFAIK its generic parameters are based on the input it get each call.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.