TornadoxFx + CoroutineScope

hi devs,

i try to integrate coroutines with tornadofx, so i try to do some think like this

val View.viewScope get() = CoroutineScope(Dispatchers.Main)

with View class, i start coroutine when view is created (with init() method)

class myView : View() {
   init() {
       viewScope.launch { ..... } 
       viewScope.coroutineContext[Job]?.children?.forEach { println(it) }

   // callback when view is dettached from scene
   fun onUndock() {

so i expected see one child print , but i find some think confuse: there is no child in viewScope !!! why ??

if i understand, any coroutine launched in scope it will be a child of this scope

This val View.viewScope get() = CoroutineScope(Dispatchers.Main) will create a new scope every time you launch something which is not good. Also since you create and forget viewScope each time, you do not call cancel() on it when your View is disposed. You may inplement a weak referenced hashmap where the key is the view and the value the CoroutineScope and “cache” it.

i not understand your reply

you say: viewScope is created and forget each time how that ???

why coroutine created in this scope is not a child ???

When using a custom getter for a field (the get() {}) you are actually creating a function. That means that each time you call your viewScope you are creating a new CoroutineScope upon which you call a .launch {}. After that the garbage collector picks up your newly generated viewScope and deletes it!

The next time you invokeviewScope it will be a completely separated, newly created CoroutineScope!

You need to save it! To do so, you may extend View into a custom view and let it implement CoroutineScope and then subclass it.


This is probably easier to understand intuitively when you switch to kotlin from java.

var foo: Int

is the same as javas

private int foo;
public void setFoo(int value) {
    foo = value;
public int getFoo() {
    return foo;

And whenever you use foo like in println(foo) the java equivalent would be println(getFoo()).

As @lamba92 said you can see that get() {} generates a function if you look at the java equivalent:

val foo: Int
    get() = TODO()
int getFoo() {
    return TODO()

In this case the compiler also creates no backing field, because you calculate the value of foo every time.