Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala types: Class A is not equal to the T where T is: type T = A

I was reading the section 20.7 of the book Programming in Scala and I was wondering why while this code compiles:

class Food
class Fish extends Food
class Grass extends Food

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


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


val bessy: Animal = new Cow

bessy eat (new bessy.SuitableFood)

This code does not (the rest of the code is the same as before, only the last line changes):

bessy eat (new Grass)

And as far as I understand the type of Grass is the same of Cow.SuitableFood.

Also, I have another question regarding this example:

If bessy is of type Animal, how can the compiler know that it needs a type SuitableFood -> Grass instead of a type Food? 'Cause trying to provide a new Food gives me a compile error of type mismatch, but the class Animal needs a type Food and the type of bessy is explicitly defined: Animal

like image 430
vicaba Avatar asked Aug 22 '15 21:08

vicaba


1 Answers

It's because bessie is declared Animal rather than Cow. bessie.SuitableFood is a "path-dependent type" (see below).

Try this:

val clarabelle: Cow = new Cow

clarabelle eat (new Grass)

This works because the compiler can deduce that clarabelle.SuitableFood = Grass from clarabelle's declared type.

Since bessie is declared Animal, not Cow, the compiler can't safely deduce that bessie.SuitableFood = Grass.* When you say new bessie.SuitableFood, the compiler generates code to look at the actual bessie object and generate a new instance of the appropriate type. bessie.SuitableFood is a "path-dependent type": the "path" (the bessie. part) that leads to the last identifier (SuitableFood) is actually part of the type. This enables you to have a custom version of a type for each individual object of the same class.


*Well, actually, I think that if the compiler were a little smarter, it could deduce that bessie.SuitableFood = Grass, since bessie is a val, not a var, and therefore won't change its type. In other words, the compiler ought to know that even though bessie is declared Animal, she's really a Cow. Perhaps a future version of the compiler will make use of this knowledge, and perhaps there's a good reason why that wouldn't be a good idea, which someone more expert than I will tell us. (Postscript: One just did! See Travis Brown's comment below.)

like image 103
Ben Kovitz Avatar answered Sep 28 '22 07:09

Ben Kovitz