In java, is an interface providing parameters to extend a parameterized interface an exact synonym of it?

Viewed 221

I would like to use an interface as a short-name for a parameterized interface, so as to avoid polluting all the code with generic syntax. For example:

EggChicken egg = chicken.lay();  // Can't make it compile.

instead of:

Egg<AnimalChicken> egg = chicken.lay(); // Compiles happily.

Say I would like to model the animals reproduction modes Using parameterized classes (https://en.wikipedia.org/wiki/Modes_of_reproduction). I have the following interfaces:

public interface Animal<T> {
   T lay();
}

interface Viviparous<T extends Viviparous> extends Animal<T> {
}

interface Egg<T extends Oviparous> {
    T hatch();
}

interface Oviparous<T extends Oviparous> extends Animal<Egg<T>> {
}

The idea being that viviparous animals lay new instances of the same animal, whereas oviparous animals lay eggs that hatch new instances of the same animal.

Now, I would like to define more precise interfaces to describe a Dog and a Chicken:

interface AnimalDog extends Viviparous<AnimalDog> {
}

interface AnimalChicken extends Oviparous<AnimalChicken> {
}

interface EggChicken extends Egg<AnimalChicken> {
}

Finally, those are the implementations:

public class AnimalDogImpl implements AnimalDog {
    @Override
    public AnimalDog lay() {
        return new AnimalDogImpl();
    }
}

class AnimalChickenImpl implements AnimalChicken {
    @Override
    public EggChickenImpl lay() {
        return new EggChickenImpl();
    }
}

public class EggChickenImpl implements EggChicken {
    @Override
    public AnimalChicken hatch() {
        return new AnimalChickenImpl();
    }
}

My problem comes when I want to use the the classes in code:

public class AnimalTest {
    @Test
    public void can_do_something_nice() {
        AnimalChicken chicken = new AnimalChickenImpl();
        // Error here:
        EggChicken egg = chicken.lay();
        AnimalChicken chick = egg.hatch();
       Assertions.assertThat(chick).isNotNull();
    }
}

I get the error: Required EggChicken, found Egg<AnimalChicken>, but this is precisely how I defined EggChicken. Is it possible to solve this kind of indirection?

2 Answers

What you are looking for is called a type alias.

Java unfortunately does not have them.

When you create a new interface, that defines a new type. An instance of EggChicken is also an instance of Egg<Chicken>, but not the other way around. You would have to make your AnimalChicken (interface!) return an EggChicken explicitly.

The overall idea is correct, but there are problems in the hierarchy. An Animal can't lay a type that is either Egg or Animal directly, they're not related. I think the following represents what you intended:

    interface LayProduct {}

    interface Animal<E extends LayProduct> extends LayProduct{
        E lay();
    }

    interface Egg<E extends Egg<E,A>, A extends Oviparous<E,A>> extends LayProduct {
        A hatch();
    }

    interface Viviparous<A extends Viviparous<A>> extends Animal<A> {    }

    interface Oviparous<E extends Egg<E,A>, A extends Oviparous<E,A>> extends Animal<E> {    }


    interface AnimalDog extends Viviparous<AnimalDog> {
    }

    interface AnimalChicken extends Oviparous<EggChicken,AnimalChicken> {
    }

    interface EggChicken extends Egg<EggChicken,AnimalChicken> {
    }
Related