Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this possible in scala def convert(f: () ⇒ Future[Int]): Future[() ⇒ Int] =?

def computeComplexNumber: () ⇒ Future[Int] =
  () ⇒
    Future {
      println("Computing complex number ...")
      Int.MaxValue
  }

def convert(f: () ⇒ Future[Int]): Future[() ⇒ Int] = ???

convert(computeComplexNumber)

Is it possible to implement convert method with above signature with condition that when convert(computeComplexNumber) is called, nothing gets printed unless you do this

Await.result(convert(computeComplexNumber), 5.seconds)()
like image 839
Pritam Kadam Avatar asked Dec 18 '22 21:12

Pritam Kadam


2 Answers

I don't see any way to do it without blocking inside convert. There is simply no way to get hold of an instance of Future[X] inside of convert, without invoking f. But once you invoke f, the Future { ... } will eagerly start to evaluate the block with the println, and produce an output.

You probably want to take a look at scalaz.concurrent.Task instead.

like image 103
Andrey Tyukin Avatar answered Dec 28 '22 23:12

Andrey Tyukin


If you want to convert () => Future[Int] to () => Int you have to wait for the result of the Future like this:

def convert(f: () ⇒ Future[Int]): Future[() ⇒ Int] =
  Future{
    () => Await.result(f(), Duration.Inf)
  }

Then

val f = convert(computeComplexNumber) // Get Future
val g = Await.result(f, Duration.Inf) // Get Function
g() // Call function

The output will not appear until you call g.


Explanation in response to comments

The question

At the core of this question is this function signature:

def convert(f: () ⇒ Future[Int]): Future[() ⇒ Int]

There is also a requirement that (in paraphrase)

f is not invoked until the returned function is invoked

Also, I am assuming that the Int in the result is the value returned by the Future in the argument, not just some random number!

The issues

The return type of the input function is Future[Int] and the return type of the output function is Int. The first is an asynchronous result and the second is a synchronous result. Any solution must therefore convert from asynchronous Future[Int] to synchronous Int. This means Await.result or something similar.

There is also a requirement that the input function is not executed until the output function is executed. This means that it must be called inside the returned function which, in turn, means that the Await.result must be called inside the returned function.

The solution

The solution above has the function signature of convert that is required by the question. It also does not invoke f until the function returned by convert is executed, which was the other requirement.

This implementation of convert is not blocking; it returns immediately with a Future value. It does not invoke f, it just returns a function that does.

The comments

There is some dispute about what it means to block inside a function, or for one function to invoke another. Blocking and invoking are processes that that happen during the execution of a function. Therefore a sensible definition of these things happening "inside" a function would be that they happen between the execution of the entry point of the function and the execution of the exit point of the function. Using this definition it is clear that the solution does not block inside the function or invoke f inside the function.

The questioner has also commented that Await.result should not be called anywhere. Unfortunately, as explained above, this is not possible because the requirement is to convert an asynchronous result into a synchronous result.

like image 43
Tim Avatar answered Dec 29 '22 00:12

Tim