scalaabstract-type

Understanding Scala use of abstract types and Classes


The next code does not compile. Why can't Santorin eat HorseFood? Tornado is declared as a new Horse, and Horse is a subtype of Animal, yet it can "eat" HorseFood.

import scala.io.StdIn._
import util._


class Food

abstract class Animal
{
    type SuitableFood <: Food
    def eat(food: SuitableFood)
}

class Grass extends Food  /*extends meaning should be "more specific than*/
class Fish extends Food
class HorseFood extends Grass

class Cow extends Animal
{
    type SuitableFood = Grass
    override def eat(food: SuitableFood) = {}
}

class Horse extends Animal
{
  type SuitableFood = Grass
  override def eat(food: SuitableFood) = {}
}

class Whale extends Animal
{
    type SuitableFood = Fish
    override def eat(food: SuitableFood) = {}

}

object abstractExample1 {

  def main(args: Array[String]) {

    val bessy: Animal = new Cow
    println("bessy = " + bessy)
    bessy eat (new Grass).asInstanceOf[bessy.SuitableFood]
     /*added this line because of a great answer someone posted for this questions but he deleted*/

    val willie: Animal = new Whale
    println("willie = " + willie)

    val santorin: Animal = new Horse
    println("santorin = " + santorin)

    val tornado = new Horse
    tornado eat new HorseFood

    print("tornado = " + tornado)
    santorin.eat(new HorseFood)

  }

}

Shouldn't this be automatically be allowed (as Horse extends Animal)? Why isn't it?

Notice that Tornado, as declared can eat HorseFood that extends Grass, and that the food parameter at the class Horse is Grass.

Is there a problem here with the = ? I mean, SuitableFood is exactly Grass and not a class C extension of Grass.


Solution

  • Santorin is an Animal not a Horse so it 'eats' 'type' not HorseFood. This is because reference to it is for Animal. Change val santorin: Animal = new Horse to val santorin: Horse = new Horse and it would work fine