InvariantDecoder

We are now going to explore this variance concept with an example. Let's start with a simple class hierarchy, as shown in the following code:

trait Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal

With this hierarchy, I can declare a variable of an Animal type and assign it to an instance of a Cat or Dog type. The following code will compile:

val animal1: Animal = Cat("Max")
val animal2: Animal = Dog("Dolly")
implicitly[Dog <:< Animal]

More generally, the assignment val a: A = b: B compiles if B <:< A.

You can check that type B extends type A with the expression implicitly[B <:< A]; if it compiles, then B is a subtype of A.

Then, we define an InvariantDecoder trait that has a single decode method. There is no + or - sign, and so InvariantDecoder is invariant on A, as shown in the following code:

trait InvariantDecoder[A] {
def decode(s: String): Option[A]
}

After this, we implement InvariantDecoder for Cat, as shown in the following code:

object InvariantCatDecoder extends InvariantDecoder[Cat] {
val CatRegex = """Cat((w+))""".r
def decode(s: String): Option[Cat] = s match {
case CatRegex(name) => Some(Cat(name))
case _ => None
}
}

InvariantCatDecoder.decode("Cat(Max)")
// res0: Option[Cat] = Some(Cat(Max)))

When we call decode with a string that matches the CatRegex regular expression, we obtain a Cat instance wrapped in an Option instance.

But what if we declare a variable of the InvariantDecoder[Animal] type? Can we assign our InvariantCatDecoder to it? Let's try it:

val invariantAnimalDecoder: InvariantDecoder[Animal] = InvariantCatDecoder

The preceding code does not compile, but the compiler is very helpful in this case. The following code is the error you will get:

error: type mismatch;
found : InvariantCatDecoder.type
required: InvariantDecoder[Animal]
Note: Cat <: Animal (and InvariantCatDecoder.type <:
InvariantDecoder[Cat]), but trait InvariantDecoder is invariant in
type A.
You may wish to define A as +A instead. (SLS 4.5)
val invariantAnimalDecoder: InvariantDecoder[Animal] =
InvariantCatDecoder
^

It tells us that if we want to make this line compile, we have to make InvariantDecoder covariant in type A. To do so, we have to add a + sign in front of the A parameter in InvariantDecoder.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset