Imagine the following object hierarchy of types:
Group
Person
Address
And then some class implementations:
ImmutableGroup
PeopleyPerson
MonsterPerson
PostalAddress
getZip() :: String
EmailAddress
getDomain() :: String
We want to allow clients of this API to use the types in a typesafe manner. So a client may want to do:
group.personAt(0).getAddress().getDomain()
And they can do that because Group is defined as:
Group<? extends PeopleyPerson<EmailAddress>> group
This means Group has to be defined as:
interface Group<A extends Address,P extends Person<A>>
We've had to make Group aware of Address even though it doesn't appear in its "runtime" API.
This smells to me. It implies any further addition to the type hierarchy requires all parents to also represent the added type in its generic declaration.
Is there a way around this?
It should be enough to have
interface Group<P extends Person<?>>
and then define the actual group instance using concrete types in the hierarchy of composition:
Group<PeopleyPerson<EmailAddress>> group
This way the consumer of the API will have type safety on the types used while maintaining each interface in the hierarchy (e.g. Group, Person, Address) agnostic of types beyond their immediate children.
See an example of such an implementation here