Tornadofx: runAsync `finally` equivalent?

Created on 9 Jul 2018  路  7Comments  路  Source: edvin/tornadofx

Good day. I wonder if there is any equivalent of finally block for runAsync block? For instance:

runAsync{
    // perform async job
} success {
    // perform success actions
} fail {
    // perform fail actions
} finally {
    // perform common actions, regardless of the callback result,
    // for instance hiding a progress bar, etc...
}

If there is no such equivalent, then what would be the most optimal solution to handle these situations?
At the moment the most optimal workaround I see is to extract finally block into function and call this function in success and fail blocks as following:

fun finalCall(){
    // perform common actions, regardless of the callback result,
    // for instance hiding a progress bar, etc...
}

runAsync{
    // perform async job
} success {
    // perform success actions
    finalCall()
} fail {
    // perform fail actions
    finalCall()
}
Enhancement

Most helpful comment

@arslancharyev31 we currently don't have a finallyextension function but I think we could add one which would be called either if the task succeeds or fails. I am currently swamped with work but I will try to add it ASP. If you have time we are always happy for PRs. In the mean time you can use your work around and call a function in both success and fail

All 7 comments

@arslancharyev31 we currently don't have a finallyextension function but I think we could add one which would be called either if the task succeeds or fails. I am currently swamped with work but I will try to add it ASP. If you have time we are always happy for PRs. In the mean time you can use your work around and call a function in both success and fail

You can also leverage the completed property. (Don't forget that you can also bind the Task's running property to a ProgressBar's visible property for the best solution to the specific requirement in your comment.)

class FinallyView : View("Finally App") {

    val running = SimpleBooleanProperty()

    override val root = vbox {

        button("Run") {

            action {

                running.value = true
                runAsync {

                    this.completedProperty.addListener( {
                        _ ->
                            println("completed")
                            running.value = false
                    })

                    println("executing")
                    Thread.sleep(5_000)

                } success {
                    println("succeeded")
                } fail {
                    println("failed")
                }
            }
        }

        label("Running" ) {
            visibleProperty().bind(running)
        }

        padding = Insets(40.0)
    }
}

OK, so based on the aforementioned responses by @nimakro and @bekwam, here's a trivial implementation of finally block:

infix fun <T> Task<T>.finally(func: () -> Unit) = (this as FXTask).apply {
        completedProperty.addListener { _ -> func() }
    }

However I'm not sure how safe it is to cast Task to FXTask. Any thoughts?

I added finally functionality to FXTask and made this extension function on Task:

infix fun <T> Task<T>.finally(func: () -> Unit) {
    if (this is FXTask<*>) {
        finally(func)
    } else {
        throw IllegalArgumentException("finally() called on non-FXTask subclass")
    }
}

Thanks @edvin. I wonder if this extension will be in 1.7.17 release?

P.S. Is there any way to implement this function with compile error, rather than run time error, in case it's being called on non-FXTask subclass?

P.S.S. There's a recursive call in the snippet you provided. The committed code is fine, though.

Yes it will :) No, that's not a recursive call, because Kotlin performs a smart cast to FXTask, it will call FXTask.finally() instead of calling Task.finally() :) I can't think of a good way to make this a compile error.

I see. Anyhow, thanks for quick response.

Was this page helpful?
0 / 5 - 0 ratings