Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Kotlin Higher-Order Functions work?

Tags:

android

kotlin

I'm struggling a bit to understand Higher-Order Functions and how to pass functions as parameters to other functions using Kotlin. I have a basic example that I want to fufill:

fun addOnSearchGameResultListener(
            activity: AppCompatActivity,
            releaseThread: () -> Unit,
            showNoResultsFoundMessage: () -> Unit,
            updateSearchResults: (result: List<Game>) -> Unit) {
        var event0017Handler: TaskExecutor = object : TaskExecutor {
            override fun executeOnSuccessTask(response: JSONObject) {
                async() {
                    uiThread {
                        try {
                            releaseThread()
                            mLoaderManager.hideIndeterminateProgressBar(activity)
                            val result = mJSONParser.getGamesByGameKey(response)
                            Log.i(GameController::class.simpleName, "response: ${result.toString()}")
                            updateSearchResults(result)
                        } catch (e: JSONException) {
                            showNoResultsFoundMessage()
                        }
                    }
                }
            }

            override fun executeOnErrorTask(payload: JSONObject) {
                releaseThread()
                mNotificationManager.showErrorPopUp(activity, payload.getString("data"))
            }
        }
        NotificationCenter.RegistrationCenter.registerForEvent(EventCatalog.e0017, event0017Handler)
    }

I'm calling the method above this way:

mGameService.addOnSearchGameResultListener(
            this,
            releaseThread(),
            showNoResultsFoundMessage(),
            updateSearchResults(null)
    )

And updateSearchResults(null) is declared as:

private fun updateSearchResults (results : List<Game>?) : (results : List<Game>?) -> Unit = {
        if (null != results && results.size > 0) {
            mLastMatchingQuery = query_container.text.toString()
            hideNoResultsFoundMessage()
            mGames = results
            mAdapter!!.dataSet = results.toMutableList()
        } else {
            showNoResultsFoundMessage()
        }
    }

I know I passed null to the func when I declared it ('cause I need to pass something at compilation time), however, the call made from inside addOnSearchGameResultListener() is not made passing the parameter from runtime, I mean, in addOnSearchGameResultListener() I always get null for results. How exactly this works and what am I doing wrong?

like image 934
E. Fernandes Avatar asked Jul 07 '16 02:07

E. Fernandes


People also ask

How do higher-order functions work?

In Javascript, functions can be assigned to variables in the same way that strings or arrays can. They can be passed into other functions as parameters or returned from them as well. A “higher-order function” is a function that accepts functions as parameters and/or returns a function.

What are the benefits of using higher-order functions?

Benefits of higher-order functionsThey are an excellent way to abstract and separate actions in a program. They are easy to reuse. They provide simplicity to the code, allowing the programmer and any other party to understand the code at a high level easily.

How does lambda function work in Kotlin?

A lambda expression is a shorter way of describing a function. It doesn't need a name or a return statement. You can store lambda expressions in a variable and execute them as regular functions. They can also be passed as parameters to other functions or be the return value.

What does :: mean in Kotlin?

?: takes the right-hand value if the left-hand value is null (the elvis operator). :: creates a member reference or a class reference.


1 Answers

I think the confusion comes from parameter names, results in particular. To resolve that you can change the updateSearchResults to i.e.:

private fun updateSearchResults() : (List<Game>?) -> Unit = { results ->
    if (null != results && results.size > 0) {
        mLastMatchingQuery = query_container.text.toString()
        hideNoResultsFoundMessage()
        mGames = results
        mAdapter!!.dataSet = results.toMutableList()
    } else {
        showNoResultsFoundMessage()
    }
}

However I do feel that it would easier to follow the code if you'd apply following changes:

  • make updateSearchResults regular method:

    private fun updateSearchResults (results : List<Game>?) {
        if (null != results && results.size > 0) {
            mLastMatchingQuery = query_container.text.toString()
            hideNoResultsFoundMessage()
            mGames = results
            mAdapter!!.dataSet = results.toMutableList()
        } else {
            showNoResultsFoundMessage()
        }
    }
    
  • change the addOnSearchGameResultListener invocation and pass a lambda

    mGameService.addOnSearchGameResultListener(
            this,
            releaseThread(),
            showNoResultsFoundMessage(),
            { updateSearchResults(it) }
    )
    
  • apply similar changes to releaseThread, showNoResultsFoundMessage

like image 75
miensol Avatar answered Sep 22 '22 13:09

miensol