The Golden Spot

I hope this helps someone who is learning about Linux and web application programming with Python, Django, and Javascript.

Friday, September 19, 2014

Method Covariance in Scala


Consider these base classes

class Dirt
class GardenItem extends Dirt {
val flavor = "seedy"
}
class Cucumber extends GardenItem {
override val flavor = "bland"
}
class Watermelon extends GardenItem {
override val flavor = "sweet"
}
class Cocktail extends Cucumber {
override val flavor = "refreshing"
}
class FruitSalad extends Watermelon {
override val flavor = "fruity"
}
view raw Base.scala hosted with ❤ by GitHub
Let's look at this method that has a covariant return value for the class GardenItem:

/**
Here is an object that has a method mixFoods which will accept
a subclass of a GardenItem and return a list of either
GardenItems or subclasses of GardenItems.
*/
object CovarianceExample {
/**
Covariance example (compiles)
def mixFoods[T >: GardenItem](food: T): List[T] = {
This method definition states that within the context of the
mixFoods method, there is a type T that is a superclass of a GardenItem.
We then go on to say that this method accepts an argument which
is of type T, a subclass of GardenItem and it returns a List of
either GardenItems or subclasses of GardenItems.
*/
def mixFoods[T >: GardenItem](food: T): List[T] = {
food match {
case x: FruitSalad => {
/**
Watermelon is a subclass of GardenItem so this is valid
to the compiler.
*/
List(new Watermelon, food)
}
case x: Cucumber => {
/**
Cocktail is a subclass of Cucumber, which is a subclass of
GardenItem so this is also valid to the compiler.
*/
List(food, new Cocktail)
}
case _ => List()
}
}
}
view raw Covar.scala hosted with ❤ by GitHub
And an example that will not compile:

/**
Here's an example of failing to return the correct type
*/
object CovarianceExampleFailFirst {
/**
Covariance example (does not compile)
def mixFoods[T >: Watermelon](food: T): List[T] = {
This method definition states that within the context of
the mixFoodsFail method, there is a type T that is either
a Watermelon or a subclass of Watermelon.
Given what we know about type T, this method will accept an argument
of type T and return a list of type T.
Unfortuanately, this code will not compile since we are
attempting to return a GardenItem within the list of what
can only contain type T.
*/
def mixFoods[T >: Watermelon](food: T): List[T] = {
food match {
case x: FruitSalad => {
/**
This will not compile because GardenItem is not a
subclass of Watermelon; it's a superclass of Watermelon.
*/
List(new GardenItem, food) // Fails!
}
case _ => List()
}
}
}
view raw CovarFail.scala hosted with ❤ by GitHub


references:
- Type Basics
- Covariance and Contravariance in Scala/