Generics And Parameter Type Hiding

Generics is an essential ingredient for a extensible and crafty design. When used wisely, generics make a programming language look good. Spiderman has reminded us repeatedly that with great power comes great responsibility. With all the extensibility we might toss the whole point type safety if generics are not used carefully. The following is a discussion about a warning often encountered.

Problem Statement :
Lets think of a scenario where the issue could be reproduced. Think of a zoo which has several animals, and habitats for these animals. Since, the habitats are designed as per the eating habits of these animals. So lets say there is a herbivore habitat where you’ll find only a herbivore.

Let me quickly highlight when will one face the type parameter hiding warnings when solving the problem.

Problem 1 :

skitch1

Lets start by knowing what type parameters are. Type parameters are the parameters we define in between < and >. Since, Animal is not a generic type, but a concrete implementation itself. The error says that, type parameter Animal is hiding the type Animal. This is simply because the compiler expects a generic type parameter here, and not a concrete implementation.
Thus, always save the concrete bounds/limitations for the implementations and subclasses.

Solution to the above described problem-

abstract class Habitat<K> {
    public abstract void getAreaInSquareYards(K k);
}

Lets go ahead and make a concrete class for out implementation.

Problem 2 :

skitch2

This is another common mistake. Here, we need to understand when we say ‘extends Habitat<HerbivoreAnimal>’, we have actually defined a type parameter, that is HerbivoreAnimal and its scope is limited to this class being defined. Writing ‘class HerbivoreHabitat<HerbivoreAnimal>’ will define another type parameter which will have nothing to do with the type parameter of the parent class.

Thus, defining HerbivoreHabitat with a Habitat<Animal> like this
skitch3
will not yeild in any compilation error or warnings.

Solution:
Not parameterizing the subclass.

abstract class HerbivoreHabitat extends Habitat<HerbivoreAnimal> {
    @Override
    public void getAreaInSquareYards(HerbivoreAnimal k) {}
}

Problem 3 :

skitch4
This is a more of a best practice. Whenever using a parameterized method inside a generic class, avoid using the type paramater used for the class whilst defining the parameterized method.

Solution:

class CompoundClass<K> {
    K k = null;

    public <V> void testMethod(V k) {}
}

————
The images used here are generated using skitch. Thank you for being patient with the experiment.


4 responses to “Generics And Parameter Type Hiding

  • Manoj Tyagi

    Hi Gaurav,

    Nice explanation about Generics

    Does Problem-2 also apply on the interfaces as well?

    interface Habitat {

    }

    if Habitat had been an interface ,giving K as type in HerbivoreHabitat would have been another type specific to HerbivoreHabitat class only(It would have had nothing to do with Habitat).
    But generally we could have generic class which extends an interface having Generic type and compiler doesn;t complain about it.

    HerbivoreHabitat implements Habitat {

    }

    -manoj

  • Joana P Lopes (@joanapl)

    Hi There

    Thinking about what u wrote… great article by the way.. What would you think about the following alternative:

    abstract class Habitat {
    public abstract void getAreaInSquareYards(K k);
    }

    If the Class Habit is always associated with an Animal as you say on your introduction you can actually scope the generic parameter by saying that regardless of the animal, it will be an animal and this won’t hide the type.

    The same logic can be applied to the rest of the points you mention.

    thoughts?

  • Gaurav

    Hi Joana. Thank you for your interest.

    Please correct me if I am wrong, but it seems you want used a generic class and ruled out the generic parameter completely reducing the code to..

    abstract class Habitat {
    public abstract void getAreaInSquareYards(Animal animal);
    }

    If that is the case, we are not using generics at all. Lets say, we wish to accommodate a mammal as well as a bird in different habitats.

    class Animal {
    public void walk();
    }

    class Bird extends Animal {
    public void flight();
    }

    class Mammal extends Animal {

    }

    Clearly, a Mammal instance can walk, but a Bird instance can both walk and fly.

    Say, if we had created a BirdHabitat using Animal and not Bird.

    class BirdHabitat extends Habitat {
    public void getAreaInSquareYards(Animal animal) {
    // I will never be able to do my mathematics here using the Bird#flight method
    }
    }

    HOWEVER!!

    class BirdHabitat extends Habitat {
    public void getAreaInSquareYards(Bird bird) {
    // I can use the Bird#flight method now 🙂
    }
    }

    And that’s why generics are beautiful.

    Please feel free to tell me that I’ve made a fool of myself by not understanding your question completely. And gave you some other answer instead.

    Thanks

Leave a comment