carlw
03/16/2017, 2:16 AMelizarov
03/16/2017, 7:27 AMpreLoginInit
, login
and postLoginInit
) into suspending functions using run(CommonPool) { … }
idiom, so that they don’t block the thread they are invoked from.
Now, I’ve extracted all your login logic into a separate function named launchLogin
. It uses launch(JavaFx) {…}
to start a coroutine in the JavaFx application thread and all the logic can be expressed sequentially inside. Every call to a suspending function will suspend it, making sure that the JavaFx app thread is not blocked. All the suspending invocations are nicely marked by the IDEA on the left-hand side.
The benefit is that you can now centralize all the error handling, by using a regular try { … } catch { … }
.
You don’t need to do anything special about getLoginInfo
, because it uses Dialog.showAndWait
which does not block the JavaFx app thread (it has its own event loop inside).
It would be way more convenient, if tornadoxfx.Rest
turns all its blocking functions into suspending functions (the same run(pool) { … ]
idiom can be used), so that you never have to worry about accidentally blocking your UI by invoking some blocking function on Rest
object.edvin
03/16/2017, 8:32 AMtornadofx.Rest
to always return suspending functions, will this have any negative impact if it's called outside of a launch
block?edvin
03/16/2017, 8:37 AMelizarov
03/16/2017, 8:42 AMsuspend fun
then you will not be able to accidentally use them from UI thread at all. The compiler will not let you just call them, which is exactly what you want. You will have to always invoke them from inside of launch
or from other kind of coroutine.elizarov
03/16/2017, 8:43 AMron
03/16/2017, 8:50 AMedvin
03/16/2017, 9:57 AMrunAsync
must use launch
, or all existing code would fail. The issue then becomes that runAsync
operates on a Task, so removing this would break compatibility. If we can still utilize a Task for this however, this would be a seamless migration.elizarov
03/16/2017, 10:41 AMrunAsync
, so that it has func: suspend FXTask<*>.() -> T)
is quite straightforward. It also good opportunity to migrate from Thread(this).start()
in the code of task
to using a pool of threads (common pool shall be fine). However, unfortunately, it does not make it automatically fully backwards compatible, because the old code could have been doing something like:
fun foo() {
runAsync { bar() }
}
fun bar() {
api.get(”something")
}
It will not “just work” if an “api.get” is a suspending function. The “bar” will have to be marked with “suspend” modifier, too. IDEA will helpfully provide a quick-fix for that, but still.
Probably, the best approach is to leave “Rest” as is (and maybe deprecate it?), but provide some alternative class with suspending functions that can be migrated to.edvin
03/16/2017, 11:09 AMelizarov
03/16/2017, 11:26 AMcarlw
03/16/2017, 11:42 AMelizarov
03/16/2017, 11:50 AMelizarov
03/16/2017, 11:50 AMkotlinx-coroutines-core
and kotlinx-coroutines-javafx
modulescarlw
03/16/2017, 11:51 AMron
03/16/2017, 2:29 PMcoRest
?ron
03/16/2017, 2:29 PMedvin
03/16/2017, 2:39 PMron
03/16/2017, 2:39 PMsexyCoRest
?edvin
03/16/2017, 2:39 PMRuckus
03/16/2017, 4:59 PMThat is how I was able to simplify your code using coroutines without adding any new utility functions to TornadoFx...Are there any utility functions you can think of off the top of your head that would make supporting coroutines easier (for this case or in general)?