I am learning Scala and I was trying to create a type class to solve the "Every animal eats food, but the type of food depends on the animal" problem. I have an Eats
type class with context bounds:
trait Eats[A <: Animal, B <: Edible]
object Eats {
def apply[A, B]: Eats[A, B] = new Eats[A, B] {}
}
with both Animal
and Edible
being abstract classes. The (reduced) Animal
interface looks something like this
abstract class Animal {
type This // concrete type
def eat[A <: Edible](food: A)(implicit e: Eats[This, B]) = // ...
}
My goal is to allow calls in the form of animal.eat(food)
only if there is an instance (an implicit value in scope) for the given type of animal and food. For this I created an EatingBehaviour
object which basically contains instances for all relations. E. g. to declare that cows eat grass I add the line
implicit val cowEatsGrass = Eats[Cow, Grass]
similar to how you would write instance Eats Cow Grass
in Haskell. However, Now i need to specify the abstract type This
for all subtypes of the Animal class for the signature in the Animal
interface to work:
class Cow extends Animal { type This = Cow }
which is redundant.
Hence my question: Can I somehow initialize the type variable This
in Animal
so that this always reflects the concrete type, similar to how I could ask for the dynamic type using getClass
?
eat
to be a method ofAnimal
or can it be on another object? – Furl