COOKIES! This blog uses cookies!
I am completely out of control of cookies here, otherwise I would have disabled them (it is controlled by the platform).
If you don't like cookies and being tracked please leave this blog immediately.

Showing posts with label functional programming. Show all posts
Showing posts with label functional programming. Show all posts

Monday, 19 October 2015

Practical generic types Contravariant and Covariant subtyping in Scala

I only found one good and simple explanation of generics Contravariance in Julien Richard-Foy’s blog:
http://julien.richard-foy.fr/blog/2013/02/21/be-friend-with-covariance-and-contravariance/

However it was not clear enough for me to memorize all these details, so I decided to develop the idea in a bit different key.

Let’s define some classification of animals:


Covariance
The easy example of covariance is a group of animals of the same kind (flock, heard, whatever...)
So the group of cows is also a group of ungulate, which is group of mammals, whch is a also group of animals:
Cow -> Ungulate -> Mammal -> Animal
Group[Cow] -> Group[Ungulate] -> Group[Mammals] -> Group[Animals]

This is covariance where Cow is a subclass of Animal, the Group[of Cow] is a (subtype of) Group[of Animal]

Contravariance
Imagine that there’s a law describing Veterinary licensing. The law defines the hierarchy of animal classes as above.
The imaginable law states that a Veterinarian with a license of some class is allowed to treat animals of subclasses of this class of animals, therefore:

LicensedVet[for Cows] can only treat Cows
LicensedVet[for Cattle] can only treat Sheep and Cows
LicensedVet[for Mammals] can only treat Dogs, Cats, Sheep and Cows
LicensedVet[for Animals] can treat anyone from this hierarchy

Cow -> Cattle -> Mammal -> Animal
LicensedVet[Cow] <- LicensedVet[Ungulate] <- LicensedVet[Mammal] <- LicensedVet[Animals]

This is contravariance here: Cow is a subclass of Animal, but LicensedVeterinarian[for cows] is not a (subtype of)  LicensedVeterinarian[for all Animals], however the LicensedVeterinarian[for Animals] is a (kind of subtype of) LicensedVeterinarian[for Cows].

This is a practical example of contravariance “from the real life” with kind of practical application.

Ok, let’s do some coding (in Scala):
class Animal(val name: String) {
  override def toString = this.getClass.getSimpleName+": "+name
}
class Mammal(name: String) extends Animal(name)
class Dog(name: String) extends Mammal(name)
class Cat(name: String) extends Mammal(name)

class Cattle(name: String) extends Mammal(name)
class Sheep(name: String) extends Cattle(name)
class Cow(name: String) extends Cattle(name)

class Bird(name: String) extends Animal(name)
class Goose(name: String) extends Bird(name)
class Chicken(name: String) extends Bird(name)

class GroupOfAnimals[A](val list: List[A]) {
  def getOne = list.head
  def getByName(name: String) = list.find({
      case p: Animal if p.name == name => true      case _ => false    }
  )
}

class LicensedVeterinarian[A] {
  def treat(a: A) = {
    print("Treat animal ")
    print(a)
  }
}

val dorothySheep = new Sheep("Dorothy")
val murkaCow = new Cow("Murka")
val gavCat = new Dog("Gav")
val unnamedHen = new Chicken("Hen")

val flockOfSheep = new GroupOfAnimals[Sheep](List(dorothySheep))
val someCattle = new GroupOfAnimals[Cattle](List(murkaCow, dorothySheep))

val jamesHerriot = new LicensedVeterinarian[Animal]
val bobbySmith =  new LicensedVeterinarian[Cattle]

flockOfSheep.getOne //Sheep: Dorothy
someCattle.getOne //Cow: Murka
someCattle.getByName("Murka") //Some(Cow: Murka)

//mr. Herriot can treat anyone
jamesHerriot.treat(dorothySheep)
jamesHerriot.treat(gavCat)
jamesHerriot.treat(unnamedHen)
//Bobby licensed only for Cattle
bobbySmith.treat(dorothySheep)
//bobbySmith.treat(gavCat) //type mismatch, expected: Cattle, actual: Cat
//bobbySmith.treat(unnamedHen) //expected: Cattle, actual: Chicken

Everything seems to work as expected, what for do we need all this covariance and contravariance things?

Imagine that vet can treat a group of animals:
class LicensedVeterinarian[A] {
  def treat(a: A) = {
    print("Treat animal ")
    print(a)
  }
  def treatGroupOfAnimals(g: GroupOfAnimals[A]) = {
    print("Treat animals ")
    print(g)
  }
}
jamesHerriot.treatGroupOfAnimals(someCattle)

If we try to compile the code with James Herriot doing treatGroupOfAnimals compiler will sipt something like:
type mismatch, expected: GroupOfAnimal[Animal], actual: GroupOfAnimal[Cattle]

What? A flock of cattle is not a group of animals? It happens because parametrized types are non-variant by default, so we must define whether it Covariant or Contravariant, otherwise it is considered to be non-variant.

Group of animals is covariant to animals, as mentioned above. So, if we redefine group of animals as follows, James Herriot will be able to treat a group of animals:
class GroupOfAnimals[+A](val list: List[A]) {
  def getOne = list.head
  def getByName(name: String) = list.find({
      case p: Animal if p.name == name => true      case _ => false    }
  )
}
jamesHerriot.treatGroupOfAnimals(someCattle) //now works as expected

Ok. What’s the use for contravariance? Let’s imagine that we have a farm:
object Farm {
  // This one will not work without covariance of GroupOfAnimals
  def areAnimalsOk(group: GroupOfAnimals[Mammal]): Boolean = {
    // Dunno am not a vet, they're always lookin fine
    true
  }
  def inviteVetForCattle(veterinarian: LicensedVeterinarian[Cattle]): Unit = {
    println("Inviting veterinarian for cattle")
  }
  def inviteVetForDog(veterinarian: LicensedVeterinarian[Dog]): Unit = {
    println("Inviting veterinarian for dog")
  }
  def inviteVetForBirds(veterinarian: LicensedVeterinarian[Bird]): Unit = {
    println("Inviting veterinarian for birds")
  }
}
Farm.areAnimalsOk(flockOfSheep) //True: They are always OK
Farm.inviteVetForCattle(bobbySmith)
// ^ This one is OK, Bobby is veterinarian for Cattle
Farm.inviteVetForCattle(jamesHerriot)
//expected:LicensedVeterinarian[Cattle],actual:LicensedVeterinarian[Animal]
Weird! Bobby can be invited to treat Cattle, but James Herriot cannot. As we said above, licensed veterinarians are contravariant to animals, so let’s try make them contravariant:
class LicensedVeterinarian[-A] {
  def treat(a: A) = {
    print("Treat animal ")
    print(a)
  }
  def treatGroupOfAnimals(g: GroupOfAnimals[A]) = {
    print("Treat animals ")
    print(g)
  }
}
Farm.inviteVetForCattle(jamesHerriot)

Phew… With contravariance option we can invite James Herriot. Our farm is safe now.

The final code:
class Animal(val name: String) {
  override def toString = this.getClass.getSimpleName+": "+name
}
class Mammal(name: String) extends Animal(name)
class Dog(name: String) extends Mammal(name)
class Cat(name: String) extends Mammal(name)

class Cattle(name: String) extends Mammal(name)
class Sheep(name: String) extends Cattle(name)
class Cow(name: String) extends Cattle(name)

class Bird(name: String) extends Animal(name)
class Goose(name: String) extends Bird(name)
class Chicken(name: String) extends Bird(name)

class GroupOfAnimals[+A](val list: List[A]) {
  def getOne = list.head
  def getByName(name: String) = list.find({
      case p: Animal if p.name == name => true      case _ => false    }
  )
}

class LicensedVeterinarian[-A] {
  def treat(a: A) = {
    print("Treat animal ")
    print(a)
  }
  def treatGroupOfAnimals(g: GroupOfAnimals[A]) = {
    print("Treat animals ")
    print(g)
  }
}

val dorothySheep = new Sheep("Dorothy")
val murkaCow = new Cow("Murka")
val gavCat = new Dog("Gav")
val unnamedHen = new Chicken("Hen")

val flockOfSheep = new GroupOfAnimals[Sheep](List(dorothySheep))
val someCattle = new GroupOfAnimals[Cattle](List(murkaCow, dorothySheep))

val jamesHerriot = new LicensedVeterinarian[Animal]
val bobbySmith =  new LicensedVeterinarian[Cattle]

flockOfSheep.getOne //Sheep: Dorothy
someCattle.getOne //Cow: Murka
someCattle.getByName("Murka") //Some(Cow: Murka)

//mr. Herriot can treat anyone
jamesHerriot.treat(dorothySheep)
jamesHerriot.treat(gavCat)
jamesHerriot.treat(unnamedHen)
//Bobby licensed only for Cattle
bobbySmith.treat(dorothySheep)
//bobbySmith.treat(gavCat) //type mismatch, expected: Cattle, actual: Cat
//bobbySmith.treat(unnamedHen) //expected: Cattle, actual: Chicken
jamesHerriot.treatGroupOfAnimals(someCattle)

object Farm {
  // This one will not work without covariance of GroupOfAnimals
  def areAnimalsOk(group: GroupOfAnimals[Mammal]): Boolean = {
    // Dunno am not a vet, they're always lookin fine
    true
  }
  def inviteVetForCattle(veterinarian: LicensedVeterinarian[Cattle]): Unit = {
    println("Inviting veterinarian for cattle")
  }
  def inviteVetForDog(veterinarian: LicensedVeterinarian[Dog]): Unit = {
    println("Inviting veterinarian for dog")
  }
  def inviteVetForBirds(veterinarian: LicensedVeterinarian[Bird]): Unit = {
    println("Inviting veterinarian for birds")
  }
}

Farm.areAnimalsOk(flockOfSheep)
Farm.inviteVetForCattle(bobbySmith)
Farm.inviteVetForCattle(jamesHerriot) 
Farm.inviteVetForDog(jamesHerriot)
Farm.inviteVetForBirds(jamesHerriot)
//Bobby is only licensed for cattle, not for birds or dogs:
//Farm.inviteVetForDog(bobbySmith) // Nope, type mismatch
//Farm.inviteVetForBirds(bobbySmith // Nope, type mismatch



Tuesday, 15 September 2015

Explaining closure pattern name

Live and learn. Indeed.

I'm currently reading a book about Scala and found that "closure" "design pattern" which I've been using in JavaScript for ages is actually from functional programming world, and this closure is not a whole thing, but a variable closing so called "open term".

Imagine the function:
function myFunc(a) {
  return a + b
}

The "a" variable here is a "bound variable", and it makes sense in context of myFunc. The "b" variable is a "free variable" and it is senseless in this context. The "a + b" expression here is an "open term". On the other hand if we replace the expression in myFunc with something like "a + 2" it will be a "closed term".

The name "closure" arises from the act of "closing" the function literal with the open term(s) by "capturing" bindings of its free variables.

var b = 2 //this b variable is actually a closure!
function myFunc(a) {
  return a + b
}

That's it. This variable is the "closure". And the thing is the "function literal" with the "open term".