Search code examples
kotlinrx-kotlin2

Lambda's are ignored until "run" is added


I have an rx chain that calls an API through Retrofit. I subscribe to my API service, with standard rx subscribe({...}) method and pass a lambda to it. Unfortunately when my call is finally completed, all the code I have added to be executed inside lambda is totally ignored. AndroidStudio suggested a fix which basically adds an inline function run to my lamda and... it magically works. I have no idea what's happening. Why does it not work without run? What does run do?

The code follows:

valuesServiceApi.getValues()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({ data ->
                run { //<- What's this?
                    val cs = data.creditReportInfo.score
                    view.setCreditScore(cs)
                    Logger.getLogger("success:").info("credit score $cs")
                }

            })

Solution

  • { expressions } is a short form of { -> expressions }, which is a function literal with zero parameters.

    Therefore,

    { data ->
        {
            val cs = data.creditReportInfo.score
            view.setCreditScore(cs)
            Logger.getLogger("success:").info("credit score $cs")
         }
    }
    

    is the same as

    { data ->
        { ->
            val cs = data.creditReportInfo.score
            view.setCreditScore(cs)
            Logger.getLogger("success:").info("credit score $cs")
        }
    }
    

    which creates a lambda expression, and do nothing with it.

    What you want to do is

    { data ->
        { ->
            val cs = data.creditReportInfo.score
            view.setCreditScore(cs)
            Logger.getLogger("success:").info("credit score $cs")
        }()
    }
    

    but this does the same as

    { data ->
        val cs = data.creditReportInfo.score
        view.setCreditScore(cs)
        Logger.getLogger("success:").info("credit score $cs")
    }
    

    plus additional function creation overhead.

    run { ... } is the same as { ... }() minus additional temporary function creation overhead. So the above is the same as

    { data ->
        run { ->
            val cs = data.creditReportInfo.score
            view.setCreditScore(cs)
            Logger.getLogger("success:").info("credit score $cs")
        }
    }