Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert CoroutineContext into Executor #1450

Closed
ZakTaccardi opened this issue Aug 20, 2019 · 7 comments
Closed

Convert CoroutineContext into Executor #1450

ZakTaccardi opened this issue Aug 20, 2019 · 7 comments
Assignees

Comments

@ZakTaccardi
Copy link

I have to use an API that accepts an Executor as a parameter. How can I create an Executor that is backed by Dispatchers.Default?

Can a CoroutineDispatcher.asExecutor(): Executor function be added to support this use case?

fun externalApi(executor: Executor)

fun example() {
  val executor: Executor = Dispatchers.Default.asExecutor()
  
  externalApi(executor)
}

Even better would be a fun CoroutineContext.asExecutor(): Executor function. I would imagine if the receiver CoroutineContext does not have a ContinuationInterceptor, this function would throw.

@ZakTaccardi ZakTaccardi changed the title Convert CoroutineDispatcher into Executor Convert CoroutineContext into Executor Aug 20, 2019
@elizarov
Copy link
Contributor

There is no "nice" public API like that, but you can already write without resorting to any kind of experimental API:

(Dispatchers.Default as ExecutorCoroutineDispatcher).executor

The only missing piece in this story is to provide a nicer API either via asExecutor extension function or via a dedicated type like DefautCoroutineDispatcher that would be implemented by Dispatchers.Default and will expose executor property on JVM. Note, that this API is related to #261.

@qwwdfsad qwwdfsad self-assigned this Aug 20, 2019
@zach-klippenstein
Copy link
Contributor

Couldn't you implement an Executor by simply forwarding Runnables to CoroutineDispatcher.dispatch with an empty context (or maybe a special uncaught exception handler)?

Or a simpler implementation that doesn't require knowing the dispatcher contracts but has a bit more overhead could just be:

CoroutineContext.asExecutor() = object : Executor {
  private val scope = CoroutineScope(this@asExecutor)

  override fun execute(command: Runnable) {
    scope.launch { command.run() }
  }
}

@elizarov
Copy link
Contributor

Ok. It's easier to implement than to discuss. See PR #1457

@ZakTaccardi
Copy link
Author

Is it doable to use a CoroutineContext or does it have to be a CoroutineDispatcher?

@zach-klippenstein
Copy link
Contributor

Any given CoroutineContext doesn't necessarily contain a dispatcher, so you'd need to provide a default dispatcher to use if the context doesn't have one (or just copy EmptyCoroutineContext semantics and always fall back to Dispatchers.Default), but what is a reasonable default probably depends a lot on your specific use case.

@ZakTaccardi
Copy link
Author

@zach-klippenstein For my use case, it would be fine to throw if the CoroutineContext does not contain a CoroutineDispatcher. I do something like the following:

AppDispatchers(
  val main: CoroutineContext = Dispatchers.Main,
  val default: CoroutineContext = Dispatchers.Default,
  val io: CoroutineContext = Dispatchers.IO,
)

CoroutineContext is preferred over CoroutineDispatcher as a type because it allows us to do something like dispatchers.copy(default = default + CoroutineExceptionHandler { ..}) (basically just the Liskov Substituion Principle)

@elizarov
Copy link
Contributor

@ZakTaccardi You can write the following simple extension for your use-case:

fun CoroutineContext.asExecutor(): Exector = 
    (get(ContinuationInterceptor) as CoroutineDispatcher).asExecutor()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants