Skip to content

Instantly share code, notes, and snippets.

@vmarquez
Last active December 23, 2015 09:49
Show Gist options
  • Save vmarquez/6617181 to your computer and use it in GitHub Desktop.
Save vmarquez/6617181 to your computer and use it in GitHub Desktop.
Two implementations of a Design by Contract Cache interface. Parametric Polymorphism is more flexible than subtype polymorphism.
case class GenericCache[A[_,_], B, C](instance: A[B,C], getf: B=>C, putf: (B,C)=>Unit) {
def retrieve(b: B) = getf(b)
def insert(b: B, c: C) = putf(b,c)
}
//Notice how neither cache implementations have to even be aware of the existnace of the typeclass. much more flexible than inheritance
class FastCache[A,B] {
private var m = Map[A,B]() //excuse mutability for illustration purposes
def add(a: A, b: B): Unit = {
m = m + (a->b)
}
def get(a: A): B = m(a)
}
object FastCache {
//This is an implicit conversion the compiler finds (for all you not as familiar with scala)
//I've put it in the companion object for convenience, but it could go in a separate file and imported
implicit def toGenericCache[A,B](instance: FastCache[A,B]): GenericCache[FastCache, A,B] = GenericCache(instance, a => instance.get(a), (a,b)=>instance.add(a,b))
}
class SlowCache[A,B] {
private var m = Map[A,B]()
def put(a: A, b: B): Unit = {
Thread.sleep(1000)
m = m + (a->b)
}
def pull(a: A): B = {
Thread.sleep(1000)
m(a)
}
}
object SlowCache {
implicit def toGenericCache[A,B](instance: SlowCache[A,B]): GenericCache[SlowCache, A,B] = GenericCache[SlowCache, A, B](instance, a => instance.pull(a), (a,b)=>instance.put(a,b))
}
object Test {
def test() {
//I want to make an important point here of why Typeclassing is better than simple function composition.
//if we just did function composition, useCache would only ever 'see' GenericCache. We could never return
//a concrete instance, with typeclasses, you have that flexibility.
val fc: FastCache[String, Int] = useCache("a", 1, new FastCache[String, Int]())
val sc: SlowCache[Char, Int] = useCache('b', 2, new SlowCache[Char, Int]())
}
def useCache[A,B,C[A,B]](a: A, b: B, cache: GenericCache[C,A,B]) = {
cache.insert(a, b)
println("getting " + cache.retrieve(a))
cache.instance
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment