I have a cache and have two functions to get an item from the cache and put an item to the cache.
When getting item(from the cache), if key not exists I need to populate a value to it and return that value.
Following is a sample code
class CacheComp {
cache = Map[String, Foo]
get(id): Foo = {
// case(id exists) => Return matching Foo
// case(id not exists) => Create a Foo and update the cache with created Foo. Then return updated Foo
}
put(id, Foo) = {
// put element to the cache
}
}
In here I'm violating single responsibility principle(SRP) of get(id)
function. How to do this without violating SRP? I can simply rename the function to getOrUpdate(id)
. But are there any clean functional programming way to do that?
If you're aiming for a 'functional' solution, you want your cache Map
to be immutable, because everything is immutable in the functional world. Note that scala.collection.immutable.Map
has this method:
override def updated [B1 >: B](key: A, value: B1): Map[A, B1]
Now there is a small wrinkle -- once the map is updated, how do you use the cache with updated value? You need to change your interface for this.
type Cache = Map[String, Foo]
object Cache {
def get(id: String, cache: Cache): (Foo, Cache) = cache.get(id) match {
case Some(e) => (e,cache)
case None =>
val foo = makeFoo
(foo, cache.updated(id, foo))
}
def put(id: String, foo: Foo, cache: Cache): Cache = cache.updated(id, foo)
}
That gives you a functional cache without side effects. I'd also further change put
to upsert
and check if a cache entry needs to be updated.