sorry for the long winded question:
Say I have a list of animals and I want to split them up like so:
BasicAnimal = {Cat, Dog}
Carnivore = {Cat, Dog, Dragon}
Herbivore = {Cat, Dog, Horse}
Now, these animals also have to live somewhere. So there's a
BasicShelter with a method shelter(animal: BasicAnimal)
Den with a method shelter(animal: Carnivore)
Shed with a method shelter(animal: Herbivore)
What's the best way to implement this in Scala? One attempt was:
class BasicAnimal extends Enumeration{
val Cat, Dog = Value
}
class Carnivore extends BasicAnimal{
val Dragon = Value
}
class Herbivore extends BasicAnimal{
val Horse = Value
}
and then
class BasicHouse{
def shelter(animal: BasicAnimal) = {//lots of code}
}
class Den{
def shelter(animal: Carnivore) = {
//again lots of code, but the cases dealing with Cat and Dog can be relegated to super.shelter
}
}
class Shed{
//the same
}
Sadly, this won't work. The Dog from Carnivore is different from the Dog in BasicAnimal. That is Carnivore.Dog == BasicAnimal.Dog returns false, so, the only way to reuse the code from BasicHouse in Den is by having a rather hacky equality method that compares the strings of the enums (or something similar). It works, but it's very unclean. Can you see any other possibilities?
As per @paradigmatic's answer, but with a few enhancements:
sealed abstract trait BasicAnimal
sealed abstract trait Carnivore extends BasicAnimal
sealed abstract trait Herbivore extends BasicAnimal
sealed abstract trait Omnivore extends Carnivore with Herbivore
case object Dog extends Omnivore
case object Cat extends Omnivore
case object Dragon extends Carnivore
case object Horse extends Herbivore
Making the traits abstract allows you to take advantage of completeness checking in pattern matches (which would otherwise warn that a match on the trait itself wasn't attempted)
The Omnivore
traits removes some duplication, and also helps with pattern matching
Using extends
instead of self typing is just plain cleaner, and more intuitive
case object
instead of object
is mostly done to better document the intent of the code, and also to provide a sane implementation of toString
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With