Reputation: 267140
I'm not sure what this pattern is called, but could this be written in scala and if so how would I go about doing this?
val userId = 1
def getUser(userId: Int): User = {
CacheLookup.getOrElse(userId) {
userDao.get(userId)
}
}
I guess this would be an anonymous function as a parameter?
Upvotes: 0
Views: 91
Reputation: 297265
There's something similar to that on maps -- check mutable map's withDefault
. The difference is that it doesn't update the map, which seems to be what you want (and, in fact, what many people using withDefault
wants, by the questions we get here).
An alternative is memoization. You'd have to find that outside the standard library, but it works a bit like that except you don't do the cache thing explicitly. Basically, you write a function userId => userDao.get(userId)
, and then you get a memoized version of it. When you call the memoized version, it will check whether there's a cached version for the parameter and serve that if so.
Note that there are important issues with the cache. Do you want/can have it increase indefinitely, or should it be limited? Will the keys expire after a time? This sort of control is important, and whatever solution you pick must support it.
As for how to implement it, it could go like this:
def memoize[A, B](f: A => B): A => B = {
var map = Map.empty[A, B]
(key: A) => {
if (!map.contains(key)) map += key -> f(key)
map(key)
}
}
val getUser = memoize((userId: Int) => userDao.get(userId))
This memoization function takes a Function1
(that is, a function with one parameter) and takes a Function1
that does caching (in a very basic sense, without any of the controls I mentioned). For functions taking more parameters you'd have to create different versions of this, or make them tupled.
Then we get to the use, where I pass the function that takes an userId
(an Int
) and returns a User
, and we get the same function back, but now doing caching.
Here's an example of tupling, just out of curiosity:
scala> val mult = memoize(((x: Int, y: Int) => x * y).tupled)
mult: ((Int, Int)) => Int = <function1>
scala> mult(2, 3)
res18: Int = 6
scala> mult(2 -> 3)
res19: Int = 6
The first call, mult(2, 3)
is actually a Scala oddity. When calling functions that take a tuple, if you are passing multiple parameters then Scala will auto-tuple then.
Upvotes: 2
Reputation: 21017
It's not entirely clear what you're asking. If you're wondering how to implement the getOrElse
method so that the database call would only be conditionally evaluated, the answer is to just use an ordinary higher-order function:
def getOrElse(userId: Int)(getter: Int => User) =
if (cache contains userId)
cache get userId
else
getter(userId)
Upvotes: 1