While examining source of Kotlin coroutines, I noticed a difference (marked with **) between JDK 8 CompletableFuture
public fun <T> future(
context: CoroutineContext = DefaultDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): CompletableFuture<T> {
require(!start.isLazy) { "$start start is not supported" }
val newContext = newCoroutineContext(context)
val job = Job(newContext[Job])
val future = CompletableFutureCoroutine<T>(newContext + job)
job.cancelFutureOnCompletion(future)
** future.whenComplete { _, exception -> job.cancel(exception) } **
start(block, receiver=future, completion=future) // use the specified start strategy
return future
}
private class CompletableFutureCoroutine<T>(
override val context: CoroutineContext
) : CompletableFuture<T>(), Continuation<T>, CoroutineScope {
override val coroutineContext: CoroutineContext get() = context
override val isActive: Boolean get() = context[Job]!!.isActive
override fun resume(value: T) { complete(value) }
override fun resumeWithException(exception: Throwable) { completeExceptionally(exception) }
** doesn't override cancel which corresponds to interrupt task **
}
public fun <T> future(
context: CoroutineContext = DefaultDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): ListenableFuture<T> {
require(!start.isLazy) { "$start start is not supported" }
val newContext = newCoroutineContext(context)
val job = Job(newContext[Job])
val future = ListenableFutureCoroutine<T>(newContext + job)
job.cancelFutureOnCompletion(future)
start(block, receiver=future, completion=future) // use the specified start strategy
return future
}
private class ListenableFutureCoroutine<T>(
override val context: CoroutineContext
) : AbstractFuture<T>(), Continuation<T>, CoroutineScope {
override val coroutineContext: CoroutineContext get() = context
override val isActive: Boolean get() = context[Job]!!.isActive
override fun resume(value: T) { set(value) }
override fun resumeWithException(exception: Throwable) { setException(exception) }
** override fun interruptTask() { context[Job]!!.cancel() } **
}
integrations, though I think of the types as nearly equivalent (except of course ListenableFuture can't be completed directly, but I don't see why this matters here). Is there a specific reason behind this difference?