execute function only once and cache value in scala - scala

I have a function like so
def runOnce(request: Request): Future[Result] = {
}
When I call this runOnce function, if it has not been run, I want it to run some method and return that result. If it has been run, I just want it to return the original result (the request coming in will be the same).
I can do it if I have no param like so
lazy val hydratedModel = hydrateImpl(request)
future for efficient filtering
def fetchHydratedModel(): Future[HydratedModelRequest] = {
hydratedModel
}
How to do in first case?

There's a general solution to this problem, which is function memoization; for a pure function (one that has no side-effects - it will not work for non-pure functions), the result of a function call should always be the same for the same set of argument values. Therefore, an optimization is to cache the value on the first call and to return it for subsequent calls.
You can achieve this with something like the following (a memoization class for pure functions with a single argument, updated—see comment below—to make it thread-safe):
/** Memoize a pure function `f(A): R`
*
* #constructor Create a new memoized function.
* #tparam A Type of argument passed to function.
* #tparam R Type of result received from function.
* #param f Pure function to be memoized.
*/
final class Memoize1[A, R](f: A => R) extends (A => R) {
// Cached function call results.
private val result = scala.collection.mutable.Map.empty[A, R]
/** Call memoized function.
*
* If the function has not been called with the specified argument value, then the
* function is called and the result cached; otherwise the previously cached
* result is returned.
*
* #param a Argument value to be passed to `f`.
* #return Result of `f(a)`.
*/
def apply(a: A) = synchronized(result.getOrElseUpdate(a, f(a)))
}
/** Memoization companion */
object Memoize1 {
/** Memoize a specific function.
*
* #tparam A Type of argument passed to function.
* #tparam R Type of result received from function.
* #param f Pure function to be memoized.
*/
def apply[A, R](f: A => R) = new Memoize1(f)
}
Assuming that the function you're memoizing is hydrateImpl, you can then define and use runOnce as follows (note that it becomes a val not a def):
val runOnce = Memoize1(hydrateImpl)
runOnce(someRequest) // Executed on first call with new someRequest value, cached result subsequently.
UPDATE: Regarding thread-safety.
In reply to the comment from user1913596, the answer is "no"; scala.collection.mutable.Map.getOrElseUpdate is not thread-safe. However, it's fairly trivial to synchronize access, and I have updated the original code accordingly (embedding the call within sychronized(...)).
The performance hit of locking access should be negated by the improved execution time (assuming that f is nontrivial).

There are likely better ways to do this depending on your setup, but a simple solution is to do the following
private var model: Option[Future[HydratedModelRequest]] = None
def runOnce(request: Request): Future[Request] = {
if (model.isEmpty) {
model = hydrateImpl(request)
}
model.get
}
If the request is indeed the same for each call, another option would be to require the request implicitly and hydrate lazily.
implicit val request: Request
lazy val hydratedRequest: Future[HydratedModelRequest] = hydrateImpl(request)

Related

Cats Effect: Avoid calling unsafeRun on external listener of T => Unit

I am using external API which offers:
def listen(listener: ResponseType => Unit): Handle
My listener returns:
IO[Unit]
Is there a way to inject my listener without a need to call unsafeRun?
listen(msg => myListener(msg).unsafeRunSync())
IO is not only container of your listener. From cats-effect documentation:
A pure abstraction representing the intention to perform a side effect,
where the result of that side effect may be obtained synchronously (via return)
or asynchronously (via callback)
it means IO contains not the some value but intention to perform some side-effect.
Here the most usual ways to work with IO:
Add some effect to the containing of IO using flatMap (this way named composition):
val ioA: IO[A] = ??? // you have some side effect returning A
// here you can have some different side effect returning B: work with DB, read some resource or so on
def aToIOB(a: A): IO[B] = ???
val ioB: IO[B] = ioA.flatMap(aToIOB)
Launching the whole chain of your combinations side effects from 1. using unsafeRunSync or similar functions which run IO. It should be called once in your application and as a rule in the end of the universe (at the end of your program).
// this line launches execution of ioA and aToIOB and will return value of B with side-effects
val b: B = ioB.unsafeRunSync()
So when you see IO[A] you should remember that it is not the similar thing as Option[A] or List[A] and you can just execute IO to get A. You should use combination of IO while your application is not on the end of execution. If so you can run it using unsafeRunSync.
I mean you should build your application without using unsafeRunSync more than one time, and I guess, your signature
def listen(listener: ResponseType => Unit): Handle
should not use IO API, but very similar to Async[F[_]] API, take a look at function async:
/**
* Creates a simple, non-cancelable `F[A]` instance that
* executes an asynchronous process on evaluation.
*
* The given function is being injected with a side-effectful
* callback for signaling the final result of an asynchronous
* process.
*
* This operation could be derived from [[asyncF]], because:
*
* {{{
* F.async(k) <-> F.asyncF(cb => F.delay(k(cb)))
* }}}
*
* As an example of wrapping an impure async API, here's the
* implementation of [[Async.shift]]:
*
* {{{
* def shift[F[_]](ec: ExecutionContext)(implicit F: Async[F]): F[Unit] =
* F.async { cb =>
* // Scheduling an async boundary (logical thread fork)
* ec.execute(new Runnable {
* def run(): Unit = {
* // Signaling successful completion
* cb(Right(()))
* }
* })
* }
* }}}
*
* #see [[asyncF]] for the variant that can suspend side effects
* in the provided registration function.
*
* #param k is a function that should be called with a
* callback for signaling the result once it is ready
*/
def async[A](k: (Either[Throwable, A] => Unit) => Unit): F[A]
Try to concentrate that listen should do in your application and choose correct signature.
Usefull links:
cats-effect IO monad
cats-effect Async typeclass

Documenting parameters of Scala functions defined via val

When documenting parameters of methods with Scaladoc, we can write:
/** Is number even
* #param i number
* #return true if i is even, false otherwise
*/
def isEvenDef(i: Int) = i % 2 == 0
Which after generating the docs (e.g. via doc from sbt) yields nice documentation of the parameters (pointless in this example, but useful in general):
However, writing an analogous function via val and using the same documentation:
/** Is number even
* #param i number
* #return true if i is even, false otherwise
*/
val isEvenVal = (i: Int) => i % 2 == 0
The param does not seem to show in the generated documentation:
Is there a way do document the parameters for functions defined via val such that they show similarly to the parameters of methods defined via def?

Scala implement inline trait method

I've started learning scala and the play framework. I downloaded the sample project from the play framework site. I have a newbie question because I cannot understand the following syntax:
def count = Action { Ok(counter.nextCount().toString) }
What exactly does it do? Action is implemented function in BaseController, where action builder is assigned.
What is the content the beetwen braces for? Wat do the braces mean in this context?
In playframework, requests are handled by Actions. When you invoke Action { ... }, you are actually invoking play.api.mvc.Action helper object to create Action values.
object Action extends ActionBuilder[Request] { ... }
If you look closely to Action object, it extends to play.api.mvc.ActionBuilder trait. This trait contains various overloaded apply methods that creates Action values. Therefore, when you are invoking Action{ ... } you are actually invoking Action.apply({...}) and this apply method is inherited from ActionBuilder trait. If you look into ActionBuilder trait, you will see various higher ordered apply functions.
Now in your case, def count = Action { Ok(counter.nextCount().toString) }
You are actually invoking apply method with default content and no request parameter.
final def apply(block: => Result): Action[AnyContent] = apply(_ => block)
That means, you are providing block { Ok(counter.nextCount().toString) } which return Ok Result.
What is the content the beetwen braces for? Wat do the braces mean in this context?
When you do Action { Ok(counter.nextCount().toString) }, you are actually invoking:
Action.apply(Ok(counter.nextCount().toString))
In scala, apply method is a factory method and therefore you don't have to essentially call apply method, therefore you can also do Action(Ok(counter.nextCount().toString)). Additionally, if your function takes only single parameter, you can replace () brackets with curly braces {}. i.e. you can do Action{Ok(counter.nextCount().toString)}.
I would suggest to look into function literals, higher ordered functions, by-name parameter, method currying etc. So, that you will have more insight in these.
The source code will give you the details:
/**
* Constructs an `Action` with default content, and no request parameter.
*
* For example:
* {{{
* val hello = Action {
* Ok("Hello!")
* }
* }}}
*
* #param block the action code
* #return an action
*/
final def apply(block: => Result): Action[AnyContent] =
apply(BodyParsers.utils.ignore(AnyContentAsEmpty: AnyContent))(_ => block)
It's equivalent to def count = Action.apply(Ok(counter.nextCount().toString))

Is Scala's Try referentially transparent?

I'm currently working on a presentation about Functional Programming, and came upon the following problem.
Functional Programming intends to separate the 'what' from the 'how', or more precisely, the declaration of a computation from its interpretation. This is why one of the main focus of this paradigm is to represent computations using composable data-structures without making any assumptions about how they are performed. For example:
// Represents a computation that may fail
case class Unsafe[A,B](run: A => B)
// ...
val readIntFromFile: Unsafe[String, Int] = Unsafe { filePath => /* ... */ }
interpret(readIntFromFile)
// Interpreter
def interpret(u: Unsafe[String, Int]): Unit = {
try {
u.run("path/to/file")
} catch {
case e => /* ... */
}
}
This seems to make sense, as side-effects should be only performed during the execution of the computation and not during its declaration. The problem is that in Scala, as it seems, many data-structures break this rule:
object Try {
/** Constructs a `Try` using the by-name parameter. This
* method will ensure any non-fatal exception is caught and a
* `Failure` object is returned.
*/
def apply[T](r: => T): Try[T] =
try Success(r) catch {
case NonFatal(e) => Failure(e)
}
}
Same for Futures:
/** Starts an asynchronous computation and returns a `Future` object with the result of that computation.
*
* The result becomes available once the asynchronous computation is completed.
*
* #tparam T the type of the result
* #param body the asynchronous computation
* #param executor the execution context on which the future is run
* #return the `Future` holding the result of the computation
*/
def apply[T](body: =>T)(implicit #deprecatedName('execctx) executor: ExecutionContext): Future[T] = impl.Future(body)
So, I'm wondering now, are Try and Future really referentially transparent? If not, then how should one handle the error cases without relying on Success and Failure?
Try is referentially transparent as long as you don't use side effects. The purpose of Try is not to control side effects, but to handle a possible exception.
If you need to control side effects in a pure way you can use Task or IO types from libraries like Cats and Scalaz.
Future is definitely not RT, since these two block are not equivalent:
The two futures are executed in parallel:
val fa: Future[Int] = service.call
val fb: Future[Int] = service.call
for { a <- fa; b <- fb } yield a + b
The two futures are executed in sequentially:
for { a <- service.call; b <- service.call } yield a + b
Try is, on the other hand. The proper functional way to handle error is to use Either[ErrorDescription, A] for a method that returns an A but might fail (you could use type ErrorDescription = Throwable for something equivalent to scala.util.Try!).

What's the meaning of new and curly brace (without type to create)?

I found the following definition in Scala Saddle and just want to be sure I understood it correctly. There is an object defining an implicit function that exposes some HDF5 I/O functionality to the Frame type so that the writeHdfFile function becomes available to any Frame:
object H5Implicits {
/**
* Provides enrichment on Frame object for writing to an HDF5 file.
*/
implicit def frame2H5Writer[RX: ST: ORD, CX: ST: ORD, T: ST](frame: Frame[RX, CX, T]) = new {
/**
* Write a frame in HDF5 format to a file at the path provided
*
* #param path File to write
* #param id Name of the HDF group in which to store frame data
*/
def writeHdfFile(path: String, id: String) {
H5Store.writeFrame(path, id, frame)
}
} // end new
}
However, I have never seen the = new { syntax before. Does it mean it is creating and returning a new function each time? why would that make more sense as opposed to simply doing = {
Its a new anonymous class with 1 function.
In this case its used to provide syntax to the frame: Frame[RX, CX, T].
With this helper class in scope you can write.
frame.writeHdfFile(...)
Without this technique you would need to write.
writeHdfFile(frame, ...)
Normally this is done with a implicit class rather than a implicit def like that.
One benefit of this technique is that you can add helper methods to a class without changing them directly. Note how writeHdfFile is not defined on Frame
This is done pretty similar to how type classes are implemented in scala.
it is creating an anonymous class. You can learn more about anonymous classes in scala here