Last active
December 23, 2015 09:49
-
-
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.
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
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