Skip to content

Instantly share code, notes, and snippets.

@wibisono
Last active April 2, 2018 16:09
Show Gist options
  • Save wibisono/383bace9c25d5a4dc718a109b6fa0818 to your computer and use it in GitHub Desktop.
Save wibisono/383bace9c25d5a4dc718a109b6fa0818 to your computer and use it in GitHub Desktop.
// Inspiration : Existensial Types (Abstract type Member) Make OOP great again! Julien R. Foy
// https://www.youtube.com/watch?v=6j5kZj17aUw
// Compare this with the type class version : https://gist.github.com/wibisono/28d8808159e0c7103042d7c5c668edf7
sealed trait Animal
case class Dog(name : String) extends Animal
case class Cat(name : String) extends Animal
trait Speaking {
type A
def speak(creature : A) : String
}
type SpeakingType[C] = Speaking {type A = C}
// Providing this instance only dog can speak
implicit val speakingDog : SpeakingType[Dog] = new Speaking {
type A = Dog
def speak(dog: Dog): String = s"I am speaking dog ${dog.name}"
}
val lassie = Dog("Lassie")
val garfield = Cat("Garfield")
// Direct usage
speakingDog.speak(lassie)
object Speaking {
def speak[C](creature : C)(implicit speakingC : SpeakingType[C]) = speakingC.speak(creature)
}
// Ok also with interface object
Speaking.speak(lassie)
//Speaking.speak(garfield)
//Error: ... could not find implicit value for parameter speakingC: SpeakingType[Cat]
// Now the interface syntax style for pimping up existing type with instances
object SpeakingSyntax {
implicit class SpeakingCreature[C](creature : C) {
def speak(implicit speakingC : SpeakingType[C]) = speakingC.speak(creature)
}
}
import SpeakingSyntax._
lassie.speak
//garfield.speak
//Error: ... could not find implicit value for parameter speakingC: SpeakingType[Cat]
implicit val speakingCat : SpeakingType[Cat] = new Speaking {
type A = Cat
def speak(cat: Cat): String = s"I am speaking cat ${cat.name}"
}
// Only now garfield can speak
garfield.speak
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment