Blog

Which Generic Swallow

12 Aug, 2010
Xebia Background Header Wave

Scene opens…
An idyllic landscape unfolds before our eyes, in yonder distance we see a figure approaching us. He goes by the name of Arthur, King of the Britons…

[code lang="java"]
public class Arthur {
// Some internals or Arthur, will be revisited later.
}
[/code]
bridge_of_deathWhen we turn around, we see a gorge. Over the gorge lies an old rope-bridge with wooden steps and on this side of the bridge, we see the BridgeKeeper.
[code lang="java"]
public class BridgeKeeper {
// Some internals of the BridgeKeeper, will be revisited later.
}
[/code]
When Arthur approaches the BridgeKeeper, the BridgeKeeper speaks: "Stop! Who would cross the Bridge of Death must answer me these questions three, ere the other side he see.".
[code lang="java"]
public class Question {
public <S> S answer(Answer<S> a) {
return a.doAnswer();
}
public interface Answer<S> {
S doAnswer();
}
}
[/code]
southafricanswalloweuropeanswallowAfter Arthur answers the first two questions correctly, the BridgeKeeper asks him the third and final question: "What is the air-speed velocity of an unladen swallow". Now our Arthur hasn’t been made king without a good reason, and knows about the differences between swallows:
[code lang="java"]
public class Swallow {}
public class EuropeanSwallow extends Swallow {}
public class AfricanSwallow extends Swallow {}
[/code]
So Arthur asks the BridgeKeeper: "What do you mean, an African or a European one?"
[code lang="java"]
public class Arthur {
public void query(BridgeKeeper keeper) {
Question whichSwallow = new Question();
Swallow s = keeper.answer(whichSwallow);
}
}
[/code]
To which the BridgeKeeper responds with: "Uhmm…. I don’t know", after which he is cast into the gorge…
[code lang="java"]
public class BridgeKeeper {
public <S extends Swallow> S answer(Question question) {
return question.answer(new Question.Answer<S>() {
public S doAnswer() {
return determineSwallow();
}
});
}
private <S extends Swallow> S determineSwallow() {
return null;
}
}
[/code]
Though this code actually looks clean, it won’t compile with your Java compiler. Though both IntelliJ and Eclipse show no errors, compiling it using the real JDK yields the following error
type parameters of <S>S cannot be determined; no unique maximal instance exists for type variable S with upper bounds S,Swallow

There is actually something fundamental here. The compiler cannot infer the correct generic type for the return value of determineSwallow(). The reasoning behind this is that the return types of determineSwallow and answer are independent. There is a long outstanding bug for this in the JDK which will now finally be fixed in Java7.
The fix is simple enough, either do an explicit cast, or call the method with the generic return type present as shown below and just ignore the warning your IDE gives you that the generic type can be inferred…
[code lang="java"]public class BridgeKeeper {
public <S extends Swallow> S answer(Question question) {
return question.answer(new Question.Answer<S>() {
public S doAnswer() {
return BridgeKeeper.this.<S>determineSwallow();
}
});
}
private <S extends Swallow> S determineSwallow() {
return null;
}
}
[/code]

Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts