Using guava's ListenableFuture with Kotlin


#1

Hi,

I can’t figure out how to use Guava’s ListenableFutures with Kotlin (I am using 1.1.1). Here’s a reference code in Java that I am trying to rewrite in Kotlin:

ExecutorService executor = Executors.newFixedThreadPool(10);
ListeningExecutorService service = MoreExecutors.listeningDecorator(executor);
ListenableFuture<Integer> future = service.submit(() -> 42);
ListenableFuture<String> transformed =
    Futures.transform(future, (Integer n) -> "[" + Integer.toString(n) + "]" , executor);
Futures.addCallback(transformed, new FutureCallback<String>() {
  public void onSuccess(String result) { System.out.println("Success: " + result); }
  public void onFailure(Throwable t) { t.printStackTrace(); }
});
executor.shutdown();

Java version works as expected and prints: “[42]” in the end.

Here’s a straightforward Kotlin conversion:

  val executor = Executors.newFixedThreadPool(10)
  val service = MoreExecutors.listeningDecorator(executor)
  val future = service.submit<Int> { 42 }
  val transformed = Futures.transform<Int?, String?>(
      future, { n: Int -> "[" + Integer.toString(n) + "]" }, executor)

  Futures.addCallback(transformed, object : FutureCallback<String> {
    override fun onSuccess(result: String?) { println("Success: " + result!!) }
    override fun onFailure(t: Throwable) { t.printStackTrace() } 
  })
  executor.shutdown()

This version doesn’t compile, here’s the error message:

e: FutTest.kt: (12, 29): None of the following functions can be called with the arguments supplied: 
public final fun <I : Any!, O : Any!> transform(input: ListenableFuture<Int?>!, function: ((Int?) -> ListenableFuture<String?>!)!, executor: ((Runnable!) -> Unit)!): ListenableFuture<String?>! defined in com.google.common.util.concurrent.Futures
public final fun <I : Any!, O : Any!> transform(input: ListenableFuture<Int?>!, function: ((Int?) -> String?)!, executor: ((Runnable!) -> Unit)!): ListenableFuture<String?>! defined in com.google.common.util.concurrent.Futures
public open fun <I : Any!, O : Any!> transform(input: ListenableFuture<Int?>!, function: Function<in Int?, out String?>!, executor: Executor!): ListenableFuture<String?>! defined in com.google.common.util.concurrent.Futures
public open fun <I : Any!, O : Any!> transform(input: ListenableFuture<Int?>!, function: AsyncFunction<in Int?, out String?>!, executor: Executor!): ListenableFuture<String?>! defined in com.google.common.util.concurrent.Futures

I tried adding mullable declarations, in and out modifiers, but wasn’t able to get this to compile. And actually it’s not the first time I ran into something like this when trying to call Java from Kotlin. Typically it’s some sort of overloaded function that uses some functional style API, and every time it’s such a bummer.

Can anyone please advise how to write such code in Kotlin or maybe a workaround? I don’t want to write that in Java everytime.


#2

Figured it out.

Apparently this works:

  val executor = Executors.newFixedThreadPool(10)
  val service = MoreExecutors.listeningDecorator(executor)
  val future = service.submit<Int> { 42 }
  val transformed = Futures.transform(
      future,
      com.google.common.base.Function { it : Int? -> "[" + Integer.toString(it!!) + "]" },
      executor)

  Futures.addCallback(transformed, object : FutureCallback<String> {
    override fun onSuccess(result: String?) { println("Success: " + result!!) }
    override fun onFailure(t: Throwable) { t.printStackTrace() }
  })
  executor.shutdown()

A type declaration on a function argument (it: Int?) is essential, without this declaration, the code doesn’t compile.

Was difficult to figure out as the error message was complaining about a Function type, and apparently a guava’s Function was expected.

The code can be made even slightly more readable with a use of a typealias:

typealias GuavaFunction<I, O> = com.google.common.base.Function<I, O>

So the code becomes just this:

  val transformed = Futures.transform(
      future,
      GuavaFunction { it : Int? -> "[" + Integer.toString(it!!) + "]" },
      executor)

Yes, still, I wonder, is it possible to do it better, without an explicit indication that it’s a GuavaFunction, and without explicit argument type declaration in an anonymous function?