Stylianos Gakis
02/03/2023, 3:03 PMclass ApplicationScope : CoroutineScope by MainScope()
And in the classes that need it I can inject it by using this type and I know which one it will get, since I am providing this as a singleton in my DI setup.
I’d like to do the same with a background dispatcher, but I can’t quite delegate like this, as CoroutineDispatcher is an abstract class, and not an interface. So I figured this compiles just fine
class BackgroundDispatcher : CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
Dispatchers.IO.dispatch(context, block)
}
}
And then in the classes where I want to provide this, I can ask for a BackgroundDispatcher
and it should be IO for prod (again providing as a singleton so it’s just one instance of this class), and for tests I can provide the alternative that I want to use per-test.
So my question is does this look odd? Any obvious problems I may be oblivious to doing something like this?kevin.cianfarini
02/03/2023, 3:07 PM@Qualifier
annotations instead.MainScope
and <http://Dispatchers.IO|Dispatchers.IO>
like the examples above.mkrussel
02/03/2023, 3:09 PMCoroutineDispatcher
has a lot of open functions that you will not be delegating to Dispatchers.IO.dispatch
, so it will probably not work the way you want.
Also I would be confused by BackgroudnDispatcher
being IO and not Default. Both are background, so the name doesn't make sense.
And like mentioned above, by tightly coupling the type to the dispatcher, you are defeating the point of injecting a dispatcher to begin with. You might as well just hard code it.Stylianos Gakis
02/03/2023, 3:12 PMkevin.cianfarini
02/03/2023, 3:13 PMCoroutineContext
.EmptyCoroutineContext
in tests without having to worry about threading.streetsofboston
02/03/2023, 3:19 PMCoroutinScope(...)
factory methods....
And if you want to be able to tell them apart when injecting them, use qualifier annotations.
Subclassing CoroutineScopes and properly implementing them is asking for trouble 🙂class ApplicationScopeWrapper(val scope: CoroutineScope = MainScope())
Stylianos Gakis
02/03/2023, 3:21 PMabstract class ApplicationScope(coroutineScope: CoroutineScope) : CoroutineScope by coroutineScope
And provide this as
single<ApplicationScope> { object : ApplicationScope(MainScope()) {} }
or something similar hmmstreetsofboston
02/03/2023, 3:21 PM.scope
to get the actual scope.Stylianos Gakis
02/03/2023, 3:22 PMclass ApplicationScope(scope: CoroutineScope = MainScope())
vs this
class ApplicationScope(scope: CoroutineScope = MainScope()) : CoroutineScope by scope
since I’m completely delegating to whatever scope
is, it really shouldn’t matter and I miss having to call .scope
each time I am using this, no?
The way I had it before
class ApplicationScope : CoroutineScope by MainScope()
was wrong since I could not replace it for tests of course, but this adjustment should be enough to let me change it for tests.streetsofboston
02/03/2023, 3:28 PMStylianos Gakis
02/03/2023, 3:32 PMApplicationScope(CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>))
Since CoroutineScope constructor itself takes CoroutineContext where I can pass that dispatcher?streetsofboston
02/03/2023, 3:38 PMclass ApplicationScope(context: CoroutineContext = EmptyCoroutineContext) : CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Main + context)
This will by default create a main-scope (https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/common/src/CoroutineScope.kt#L118) and allow you to override stuff through the context
parameterStylianos Gakis
02/03/2023, 3:43 PMclass ApplicationScope(scope: CoroutineScope = MainScope()) : CoroutineScope by scope
no? Like I’m not sure what this last suggestion will help me with in terms of ease of use in my tests compared to passing an entire CoroutineScope? Passing the entire CoroutineScope will also allow me to pass backgroundScope from inside TestScope
if that’s what I need to use. With your impl that would make it harder no?coroutineContext: CoroutineContext,
without the information of the qualifier, and I need to make sure I remember to pass it in on the place where I am constructing it, like coroutineContext = get(ioDispatcherQualifier)
. Let’s hope I don’t change this somehow and forget to do the same thing some months in the future 😅