ghedeon
01/17/2019, 9:47 PMfun main(){
runBlocking{
with(First()){
with(Second()){
with(Third()) {
foo().zip(bar()).zip(foo()) // fails because of name conflict
}
}
}
}
}
class First(){
fun CoroutineScope.foo():ReceiveChannel<Int>{}
}
class Second(){
fun CoroutineScope.bar(): ReceiveChannel<Int>{}
}
class Third(){
fun CoroutineScope.foo(): ReceiveChannel<Int>{}
}
Deep nesting plus name conflicts. How do you tell the difference between the two methods with the same name?gildor
01/18/2019, 12:51 AMghedeon
01/18/2019, 1:27 AMCoroutineScope
but there is no lifecycle attached to it. What about the cleanup in this case? Do you still have to do anything about the Job?Dico
01/18/2019, 1:29 AMghedeon
01/18/2019, 1:35 AMSomething wrong anyway
is not very constructive.Dico
01/18/2019, 1:39 AMdave08
01/18/2019, 4:00 AMproduce
in a coroutineScope { }
to use the callers scope? @ghedeongildor
01/18/2019, 4:31 AMWhat about the cleanup in this case? Do you still have to do anything about the Job?Just pass coroutine scope as argument
dave08
01/18/2019, 8:13 AMgildor
01/18/2019, 8:14 AMit looks like he’s right that rx leads to a cleaner api in this regardIt’s not true. Rx by default do not force you to handle lifecycle. You can do exatly the same with Kotlin if you want:
fun bar() = GlobalScope.produce()
- this is exactly what RxJava does in terms of lifecyclefun bar(scope: CoroutineScope) = scope.produce()
is not worse than
fun CoroutineScope.foo() = produce()
This is just a matter of style and use casedave08
01/18/2019, 8:22 AMgildor
01/18/2019, 8:25 AMbut in rx you handle the lifecycle at subscription using composite subscriptions
val compositeChannel: MutableList<ReceiveChannel<T>>
compositeChannel = GlobalScope.produce { } // do some subscription
compositeChannel.forEach { it.close() }
coroutines force you to handle it in the repositories and in all usagesAnd this is good, not bad
produce
runs coroutinesubscribe()
methoddave08
01/18/2019, 8:32 AMgildor
01/18/2019, 8:32 AMdave08
01/18/2019, 8:34 AMgildor
01/18/2019, 8:35 AMghedeon
01/18/2019, 9:14 AMfoo/foo
in my example? Because I didn't find it yet. Only the last one wins.Dico
01/18/2019, 9:17 AMgildor
01/18/2019, 9:18 AMval firstFoo = with(First()) { foo() }
val bar = with(Second()) { bar() }
val thirdFoo = with(Third()) { foo() }
firstFoo.zip(bar).zip(thirdFoo)
ghedeon
01/18/2019, 9:24 AMgildor
01/18/2019, 9:25 AMval firstFoo = First().foo(scope)
val bar = Second().bar(scope)
val thirdFoo = Third().foo(scope)
firstFoo.zip(bar).zip(thirdFoo)
ghedeon
01/18/2019, 9:28 AMgildor
01/18/2019, 9:29 AMclass First {
fun CoroutineScope.foo() = produce {}
fun CoroutineScope.bar() = produce {}
fun CoroutineScope.baz() = produce {}
}
Than usage with sccope is quite nice:
with(First()) {
foo().zip(bar()).zip(baz())
}
with
is just a way to bring extension to scope, nothing moreghedeon
01/18/2019, 9:42 AMgildor
01/18/2019, 9:56 AMIt’s basically every second Interactor in your app: take a few repos, combine channels, give it to ViewModelAnd all your sources of observables have name conflicts? Not every ViewModel has so many separate sources, of course it’s possible, I just want to say that it not something that you have all the time
bdawg.io
01/23/2019, 4:25 PMclass Foo { fun CoroutineScope.bar() = ... }
can be invoked as foo.bar(scope)
without rewriting the extension function signatureDico
01/23/2019, 4:32 PMelizarov
01/24/2019, 11:21 AM