3

Situation: I'm making a configuration library, with a Config interface that represents the data, and a Parser interface like this:

public interface Parser<C extends D, D extends Config> {
    C parse(File f);
    void parse(File f, D destination);
}

The parser must be able to parse data into a new Config object (C), or an existing one (D). C extends D because it's logical that we can create C manually and parse data into it. And of course D extends Config because we parse configurations.

Let's say we have a class MyConfig that implements Config (but it could as well be a generic "T extends Config"), and we want a Parser that can create and parse it. Let's follow the PECS rule:

  • Our parser can parse MyConfig, but maybe supertypes of it too => I should use "? super MyConfig"
  • Our parser can produce MyConfig, but maybe it actually produces a subtype => I should use "? extends MyConfig"

Therefore I end up with this:

Parser<? extends MyConfig, ? super MyConfig> parser;

But while IntelliJ doesn't complain about anything, the compilation (javac 1.8.0_131) fails with this error:

type argument ? extends package.MyConfig is not within bounds of type-variable C

Which is weird, because "some subtype of MyConfig" is obviously a subtype of "some supertype of MyConfig", right?

This issue arises only when both wildcards are used. Also, using another generic type instead of the upper bound works:

// All these are fine
Parser<? extends MyConfig, MyConfig>
Parser<MyConfig, ? super MyConfig>
<J extends MyConfig> void test(Parser<J, ? super MyConfig> parser)

What am I missing here? And what can I do with my producer-consumer Parser?

EDIT: I found something even more confusing: using a subinterface of Config instead of a subclass works, ie this compiles perfectly fine:

interface SpecialConfig extends Config {}
Parser<? extends SpecialConfig, ? super SpecialConfig> specialParser;
ElectronWill
  • 754
  • 9
  • 17
  • Very little type information propagates through wildcards. I don't think the compiler propagates the `super MyConfig` information to the bounds-checking for `? extends MyConfig`. – user2357112 Jul 15 '17 at 00:11
  • `Parser extends MyConfig, ? extends MyConfig>` also seems to compile and I think that's actually less provably-correct than `Parser extends MyConfig, ? super MyConfig>`. Go figure, I guess. I don't have a good answer but I'm not really surprised there are issues with this. – Radiodef Jul 15 '17 at 00:34
  • @user2357112 Well I've found that using a subinterface like SpecialConfig instead of a class like MyConfig is accepted. So in one case the info seems to propagate, and in the other it fails... but using interface instead of class should not make any difference in that case! The compiler seems to have some problem. – ElectronWill Jul 15 '17 at 21:42

0 Answers0