Search code examples
scalatypes

In Scala how do I define upper type bounds that are exclusive of the defined class?


Given a concrete class Animal, how do I define a function that only takes a subclass of Animal?

In typical examples like this Animal is a trait so defining [A <: Animal] implies that you already pass in a subclass of Animal. However, in a scenario like below where Animal is concrete, can I exclude that as being an allowed type?

I'm working with existing generated code, and this is just a generalized example of the problem. Therefore the implication is that I can't make Animal (or the equivalent) into a trait.

See below for an example:

class Animal {
  def name: String = "General Animal"
}

class Dog extends Animal {
  override def name: String = "Dog"
}

// How do I limit A to be a subtype of Animal (excluding Animal itself)?
class SpecificAnimalContainer[A <: Animal](a: A) {
  def specificAnimal: A = a
}

val dogContainer = new SpecificAnimalContainer[Dog](new Dog)

// I do not want this to be able to compile.
val animalContainer = new SpecificAnimalContainer[Animal](new Animal)

Solution

  • Using shapeless you can write:

    import shapeless._
    
    class SpecificAnimalContainer[A <: Animal](a: A)(implicit ev: A =:!= Animal) {
      def specificAnimal: A = a
    }
    
    //  val animalContainer = new SpecificAnimalContainer[Animal](new Animal)// doesn't compile
    

    Otherwise you can implement similar type for implicit yourself.

    Type constraint for type inequality in scala

    Enforce type difference

    How can I have a negation type in Scala?