Kotlin delegating to a future

java, kotlin

Solution

You can translate your Java code to Kotlin in a straightforward way using custom property getters:

class Example(fooId: Int) {
    private val fooFuture = supplyAsync { httpClient.get(fooId) }

    val foo: Foo
        get() = fooFuture.get()
}

But Kotlin has a more powerful concept for generalizing property behavior -- the property delegates:

class Example {
    val foo: Foo by someDelegate
}

In this example, `someDelegate` is an object that defines the behavior of property `foo`.

Though `Future<V>` cannot be used as a delegate out of the box in Kotlin, you can create your own property delegates by implementing `getValue(thisRef, property)` and (for mutable properties) `setValue(thisRef, property, value)` functions, thus explicitly providing the code to be executed when a property is read (and written, if mutable).

These functions can be either member functions for your project classes or extension functions, which fits the case with `Future<V>`. Basically, to use `Future<V>` as a property delegate, you have to define the `getValue(thisRef, value)` extension function for it, for example:

operator fun <V> Future<V>.getValue(thisRef: Any?, property: KProperty<*>) = get()

Here, the value the delegate will provide for a property will be simply taken from the `Future::get` call, but a proper implementation should probably take care of cancellation and exceptions handling. For this purpose, you can wrap a `Future<V>` into a class that will also define the fallback values/strategies, and then use this class' objects in `by`.

Then you can use `Future<V>` objects as delegates for your properties:

class Example(fooId: Int) {
    val foo: Foo by supplyAsync { Thread.sleep(2000); fooId }
}

fun main(args: Array<String>) {
    val e = Example(123)
    println(e.foo)
}

Problem

I am trying to learn Kotlin and delegates are both interesting and confusing. I have a situation where, in a java class I would take a constructor arg, create a Future (the ID represents a resource in another system) and stash the Future as an instange variable. Then the "getXXX" would call `Future.get()` Here is a sample java class ``` public class Example { private Future<Foo> foo; public Example(String fooId) { this.foo = supplyAsync(() -> httpClient.get(fooId)); } public Foo getFoo() { return foo.get(); } } ``` I am not supplying the Kotlin example because I am simply not sure how to construct it.

Original source