Generics class type constraints , possible?


#1

I am not sure how to describe my question , see this code below

sealed class Animal(val type: String) {
  data class Cat(val color: String) : Animal("cat")
  data class Dog(val mood: String , val ownersName : String) : Animal("dog")
}

abstract class AnimalDescriptor<out T : Animal>(val a: T) {
  abstract fun getSummary(): String
}

class CatDescriptor(a: Animal.Cat) : AnimalDescriptor<Animal.Cat>(a) {
  override fun getSummary(): String {
     return "The color of this ${a.type} is ${a.color}"
  }
}

class DogDescriptor(a : Animal.Dog) : AnimalDescriptor<Animal.Dog>(a) {
  override fun getSummary(): String {
    return "${a.ownersName}'s ${a.type} is ${a.mood}"
  }
}

fun main(args: Array<String>) {

  fun summary(a : Animal) : String {
    return when(a) {
      is Animal.Cat -> CatDescriptor(a)
      is Animal.Dog -> DogDescriptor(a)
    }.getSummary()
  }

  val kitten = Animal.Cat("yellow")
  val doggy = Animal.Dog("happy" , "John")

  println(summary(kitten))
  println(summary(doggy))
}

The output is

The color of this cat is yellow
John's dog is happy

It works as I want.
But I feel a little ‘fishy’ , because the duplicated type declaration in the initialization of AnimalDescriptor :

class CatDescriptor(a: Animal.Cat) : AnimalDescriptor<Animal.Cat>(a)

It duplicates Animal.Cat here. Is there any way to eliminate any of this ?

Moreover , it cannot forbid us writing this class :

class ADescriptor(a : Animal) : AnimalDescriptor<Animal>(a) {
  override fun getSummary(): String {
    return "type = ${a.type} "
  }
}

Which is meaningless in this case… Is there a better design ?

(functional style or even Kategory incorporation is welcome)


#2

If you declare the animal as a property on the leaf descriptors you don’t need generics (and you will not leak that implementation detail to the environment). Actually your AnimalDescriptor class can become an interface.