Any way to use the `suspend fun main` bridge machi...
# coroutines
y
Any way to use the
suspend fun main
bridge machinery in a test? I have a library that does some coroutines magic, and I want to test that it works even in
suspend fun main
and all the missing things that that entails (no
Dispatcher
or
Interceptor
).
j
hmm is that just like
CoroutineScope(EmptyCoroutineContext)
or something? Maybe plus a
Job
?
Would have to check what it generates. You could probably also call into whatever it calls into with some ill-advised suppressions.
y
I doubt it has a
Job
since that's
kotlinx-coroutines
. I'll have a look at what it generates! Was just wondering if there's some official-ish way instead of going down this rabbit-hole. I remember from digging a while back that the implementation is platform-specific or something, which might be annoying since I'll have to do 3 different behaviours.
Looking at the bytecode. It seems to simply just call
kotlin.coroutines.jvm.internal.RunSuspend
, which is a very simple implementation. I think I'll either use it and suppress the invisible error, or just copy that implementation.
today i learned 1
JS seems to just do:
Copy code
function mainWrapper() {
    main(get_EmptyContinuation());
  }
Where EmptyContinuation is just
Continuation(EmptyCoroutineContext) { result -> result.getOrThrow() }
I can't find what native does by just looking on Github. I'll look through the compiled code later
e
you can't use
suspend fun main()
on native. https://youtrack.jetbrains.com/issue/KT-52753
👍 1
k
Separate, but I don't really see the value add of
suspend fun main
.
The gap it currently fills is a suspending entry point across all platforms, of which js is notably annoying to hand roll
But that could possibly be better served by a fully cross platform bridging function in kotlinx
e
suspend fun main()
is the only reasonable recourse for top-level async in Kotlin/JS IMO
k
I don't see any reason why it has to be implemented in the stdlib though. Why couldn't it be an entrypoint function similar to
runTest
? eg.
Copy code
// on kotlin/JS
fun main = runSuspendingEntrypoint { ... }
suspending main functions are documented primarily as a good entrypoint into kotlinx-coroutines, but it's missing specific features. Notably, it's not cancellation aware and calls to
delay
on concurrent platforms will spin up the default delay on additional threads. In contrast, runBlocking's event loop implements delay so no additional threads are required.
e
the whole
actual typealias TestResult
being a completely different type is an incredible hack and makes it far too easy to accidentally discard
k
Far too easy to discard by who? I don't really think that people using
runTest
ever think about it, and instead the library maintainers are the ones who have to manage the test result. Wouldn't the same hold true here?
y
From what I can see,
suspend fun main
doesn't use the
TestResult
mechanism or promise-returning or anything like it. It just passes an empty continuation to
main
, so I'm not sure if discarding is a concern here.
👍 1
k
From what I understand the whole
TestResult
dance is to make sure that exceptions are reported properly in tests from JS. I'm not sure that'd be required for a top level suspending entrypoint. For example, it might be a quirk of the JS test runner. I'm not certain, though
j
It's not about exceptions, it's because if you suspend then you have to return a promise which gets awaited by the test frameworks
👍 1
Otherwise your test will complete at the first suspend point
The
TestResult
type exists to abstract over the need to return a value (or not) from common code. The
suspend fun main
feature is in the language and implemented by the compiler, so even if it did need to return a promise it could do so directly as there's no common library API here.
k
Right, but the current implementation of
suspend fun main
shows that there's not any actual real need for the compiler to support this. A common entrypoint offered in kotlinx-coroutines could simply be: • Run the function with a new continuation on JS, and • an alias for runBlocking elsewhere
The documentation shows you should:
Copy code
suspend fun main() = coroutineScope { ... }
And on multi threaded platforms this is strictly worse than runBlocking imo
y
I don't know about "an alias for `runBlocking`" because that's kotlinx-coroutines API. I can see the case for having some
runSuspend
function that does what the
suspend fun main
currently does. I think the fear is maybe that it'd be misused? I also like the elegance of having
suspend
literally to the entry point of the application, but that's aesthetics and nothing else.
k
I suppose I should be clear that I don't think it makes sense to offer a suspending entrypoint with only the stdlib at all
The code looks nice, sure, but supporting stuff with it is kinda annoying
I think the fear is maybe that it'd be misused? I also like the elegance of having
suspend
literally to the entry point of the application, but that's aesthetics and nothing else.
This issue is perhaps also relevant.