hello! question about subroutines i have this code...
# server
m
hello! question about subroutines i have this code:
Copy code
object LoggingAsyncRunner {

    private val log: Logger = LoggerFactory.getLogger(this.javaClass)

    fun launch(job: () -> Unit) {
        CoroutineScope(Dispatchers.Default).launch {
            runHandlingErrors(job)
        }
    }

    private fun runHandlingErrors(job: () -> Unit) =
        try {
            job()
        } catch (e: IllegalArgumentException) {
            log.warn("Async job exception", e)
        } catch (e: Exception) {
            log.error("Async job exception", e)
        }
}
this cannot handle
delay
, so I change
job: () -> Unit
to
job: suspend CoroutineScope.() -> Unit
, and also add
suspend
to
fun runHandlingErrors
Copy code
object LoggingAsyncRunner {

    private val log: Logger = LoggerFactory.getLogger(this.javaClass)

    fun launch(job: suspend CoroutineScope.() -> Unit) {
        CoroutineScope(Dispatchers.Default).launch {
            runHandlingErrors(job)
        }
    }

    private suspend fun runHandlingErrors(job: suspend CoroutineScope.() -> Unit) =
        try {
            job(~)
        } catch (e: IllegalArgumentException) {
            log.warn("Async job exception", e)
        } catch (e: Exception) {
            log.error("Async job exception", e)
        }
}
now I get an error in fun runHandlingErrors inside try block (marked with ~) saying:
no value passed for parameter p1
I then add CoroutineScope receiver to fun runHandlingErrors, and I get this warning:
Screenshot 2022-02-19 at 15.02.27.png
now if I let IDEA do its thing, it makes this:
Copy code
private suspend fun runHandlingErrors(job: suspend CoroutineScope.() -> Unit) =
    coroutineScope {
        try {
            job()
        } catch (e: IllegalArgumentException) {
            log.warn("Async job exception", e)
        } catch (e: Exception) {
            log.error("Async job exception", e)
        }
    }
it adds
coroutineScope {
I do not understand what's happening here, and I failed a google check, please help me
basically I need to write a wrapper around a suspend function
s
I would remove the
CoroutineScope
receiver from your
job
, so it's just:
Copy code
job: suspend () -> Unit
Unless you think you need it for some reason?
m
huh
s
Generally speaking, functions should either suspend or extend
CoroutineScope
, but not both
m
thank you!!
s
(The fact that
launch
accepts a
suspend CoroutineScope.() -> Unit
is a bit of an oddity which I find it best to ignore 😂)
m
one more question please
is there a practical difference between
Copy code
private fun runHandlingErrors(job: () -> Unit) =
        try {
            job()
        } catch (e: IllegalArgumentException) {
            log.warn("Async job exception", e)
        } catch (e: Exception) {
            log.error("Async job exception", e)
        }
and
Copy code
private fun runHandlingErrors(job: () -> Unit) =
        try {
            job()
        } catch (e: IllegalArgumentException) {
            log.warn("Async job exception", e)
            throw e
        } catch (e: Exception) {
            log.error("Async job exception", e)
            throw e
        }
throwing error after logging it
I suspect the difference might come up if I have parent coroutines and child coroutines?
s
That's exactly right 👍. Errors which are thrown inside
launch
or
async
will propagate upwards to the parent job, until they reach the root job (which is normally a coroutine scope).
In your case, you're creating a new root coroutine scope for every job, and you're not installing any error handling behaviour into that scope. That means that right now, there's no practical difference between your two code examples.
m
what if i change launch to async?
well, basically i need to throw errors for async, or return null, or something
thank you very much for your help!
s
async
will return a
Deferred
which you can use to see if the job threw an exception. In that case, your first example would make it always appear successful, while the second example would ensure the
Deferred
also fails with the appropriate exception
👍 1
(
async
still cancels its parent job too, but that doesn't affect your example)