Created
October 9, 2017 12:51
-
-
Save JamesMenetrey/1c63ba43d1a7f014dc99227c5f7c6e0b to your computer and use it in GitHub Desktop.
Abstract type members in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package scalaInAction.chapter8ScalableExtensibleComponents | |
import org.scalatest.{FlatSpec, Matchers} | |
class Food | |
class Grass extends Food | |
abstract class Animal { | |
type SuitableFood <: Food // Upper bound (<:) | |
def eat(food: SuitableFood): String | |
def create: SuitableFood | |
} | |
class Cow extends Animal { | |
type SuitableFood = Grass | |
override def eat(food: SuitableFood): String = s"The cow eats ${food.getClass.getSimpleName}." | |
def create: SuitableFood = new SuitableFood // underlying Grass | |
} | |
object ComplexFactory { | |
def get: Animal = new Cow | |
} | |
class AbstractTypeMembers extends FlatSpec with Matchers { | |
"Abstract type members" can "returns its abstract type to reference compatible types" in { | |
val cow: Cow = new Cow | |
val grass: cow.SuitableFood = new Grass | |
cow.eat(grass) | |
} | |
"Abstract type members" can "wisely understand that types passed by argument are compatible with their abstract types." in { | |
val cow: Cow = new Cow | |
cow.eat(new Grass) | |
} | |
"Abstract type members" must "be type-safe, by checking the type of the argument" in { | |
val cow: Cow = new Cow | |
// Can't compile because a cow cannot eat any type of Food | |
"cow.eat(new Food)" shouldNot compile | |
} | |
"Abstract type members" must "enforce the abstract type when the variable is not of the type of the underlying class" in { | |
val cowAsAnimal: Animal = new Cow | |
// Can't compile because an animal can only eat a SuitableFood | |
"cowAsAnimal.eat(new Food)" shouldNot compile | |
"cowAsAnimal.eat(new Grass)" shouldNot compile | |
} | |
"Abstract type members" can "return method dependent types are handle them back" in { | |
val cowAsAnimal: Animal = new Cow | |
val foodForCow: cowAsAnimal.SuitableFood = cowAsAnimal.create | |
cowAsAnimal.eat(foodForCow) should be ("The cow eats Grass.") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment