Which Generic Swallow

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...

public class Arthur {
	// Some internals or Arthur, will be revisited later.
}

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.

public class BridgeKeeper {
	// Some internals of the BridgeKeeper, will be revisited later.
}

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.".

public class Question {

	public <S> S answer(Answer<S> a) {
		return a.doAnswer();
	}

	public interface Answer<S> {
		S doAnswer();
	}
}

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:

public class Swallow {}

public class EuropeanSwallow extends Swallow {}

public class AfricanSwallow extends Swallow {}

So Arthur asks the BridgeKeeper: "What do you mean, an African or a European one?"

public class Arthur {
	public void query(BridgeKeeper keeper) {
		Question whichSwallow = new Question();
		Swallow s = keeper.answer(whichSwallow);
	}
}

To which the BridgeKeeper responds with: "Uhmm.... I don't know", after which he is cast into the gorge...

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;
	}
}

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...

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;
	}
}

Comments (1)

  1. [...] This post was mentioned on Twitter by Jeroen van Erp, Xebia BV. Xebia BV said: New blog post: Which Generic Swallow http://blog.xebia.com/2010/08/12/which-generic-swallow/ [...]

Add a Comment