`fun ReceiveChannel. toDeferred() = async { singl...
# coroutines
d
fun ReceiveChannel. toDeferred() = async { single() }
, @spierce7 maybe, but probably not such good practice in coroutines to do such a thing though...
s
why not a good practice to do such a thing?
d
Coroutines is a whole different way of looking at concurrency, it doesn't need composition as much as Rx, but rather supports linear code just as if there wasn't any concurrency and everything was running on one thread. You shouldn't really need to use Deferred or any coroutine launcher so often, only at the outer level of code, the rest should all be suspend fun... @Jonathan explained this very well in one of the Github coroutine issues, I can't find it right now though 🙁
s
How would you recommend I do this without using Channel? I need a bridge (similar to rx Subject) between the coroutine world and the non coroutine world:
Copy code
class AuthWorkflow : AbstractWorkflow<Unit, Unit>() {
  protected val resultChannel = Channel<Unit>()
  
  override fun start(input: Unit): Deferred<Unit> {
    return resultChannel.toDeferred()
  }
  
  override fun abort() {
  }
  
  fun finish() {
    resultChannel.offer(Unit)
  }
}
d
You need this to be called in Java? Otherwise, you could make
start
into a
suspend fun
and call
single()
or
receive()
. The Channel is fine, the deferred might not be necessary...
But for one result, why do you need a Channel?
You could have a suspend fun return the result straight away..
s
because the result won't return until a later time.
the example I showed is incomplete. Basically something will call
start
and receive a deferred back. The deferred won't have a result until the AuthWorkflow is complete, at which point it will return, return and the person who called start() will then be notified
Is there a better way to do this with coroutines. I admit I am stuck in an rx world in my mind
d
It doesn't matter that the result is not till later, it'll suspend just as long as whatever you're calling that needs to be waited for is adapted to suspend too... @spierce7
s
Can you show me in code? How would I have that function suspend, and then stop from suspending when the result is there?
d
What do you need to wait for in there @spierce7 ?
If it's Retrofit, there's a few libs to
await()
the result.. then you call that in your suspend function and until the result is not there, it won't return
Coroutines are like a callback, suspending happens until the "callback" receives the result, but instead of having to wrap all the code in a lambda, it just returns the result to the next instruction in the coroutine flow.
s
So it's probably in most cases awaiting user input. In the case of the AuthWorkflow, the
start
function is called when the user first goes to the auth / login page, and the
Deferred
that will return from it will complete when the user successfully logs in
make sense?
d
You're on Android using a WebView? Or using an httpclient to log in? If so, one of them should have a callback you can wrap into a
suspend fun login()
function...
On Android if I want to request a Permission, I have the following: https://gist.github.com/dave08/f8d6a717f25b426e00fcfabc73b7197d.
That way my code is linear...
s
no, I'm not using a webview.
d
so you don't need a whole class for login... nor a callback.. you just call
login()
as if it would return right away and let it suspend until the result comes in, the next steps will be stored in a continuation until the result arrives, and then the code continues
What are you using? Retrofit?
Another client?
s
no
this isn't an http call
d
So what is it? Any lib. you can point to?
s
no, home grown lib
basically, start is called, and it will show the auth screen
d
How do you get a result? With a callback?
s
and
start
returns a
Deferred
, and that
Deferred
, won't complete until after the user has successfully logged in
make sense?
d
How do you get the Deferred? Where is it coming from? You need to go to the root to see if it can be turned into a suspend fun...
A callback can be adapted like in my gist
s
That's what I'm trying to figure out. Where does the deferred come from? The only way I've found to do it is to take a channel, and then have it return a deferred
is there a way for me to instead of taking a channel and convert it to a deferred, to just use a deferred from the start?
d
Yes,
CompletableDeferred
. But you need to call it from some callback or something...
Same as my gist, but instead I make a
suspend fun
s
CompletableDeferred
is exactly what I need
thanks 🙂
d
Deferred can also used when you need to run blocking api in
async(MyThreadPool) { ... }
and you get a Deferred as a result
But only when you don't have any callbacks to use...
s
thanks 🙂
d
Good luck 😉