dazai
dazai

Reputation: 716

Return a function (that returns a string) inside a function with kotlin

I'm trying to return a function (that returns a string) inside of function but, since I haven't made this explicit (I'm not sure how to make it so that the function knows it'll return a function), I get kotlin.Unit as a result.

This is the function:

fun takeOutArticle(code:String) {

       fun onSuccess(finalPrice: Int): String {
           return "Your price is $finalFee."
       }

       fun onError(): String {
           return "Error."
       }

       val articlesCode = house.articles.find{ it.code == code }
       if (articlesCode != null) {
           val finalPrice = calculatePrice(
               articleType = articlesCode.articleCode,
               finalTime = articlesCode.finalTime.toInt(),
               hasCard = !articlesCode.Card.isNullOrEmpty())

           onSuccess(finalPrice)
       } else {
           onError()
       }

So when I call the function and whether it's successful or not, it returns unit but I'd need it to return the string inside of onSuccess or onError. How can I do this? Thank you.

Upvotes: 1

Views: 3575

Answers (1)

amanin
amanin

Reputation: 4139

  1. When returning a value from a function you have to specify the return type in function signature (after the name and arguments). Source: Function syntax.
  2. Apart from lambdas, you need to add a return keyword in front of the return value / expression. Note that if/else is an expression.
  3. Note that you can return the result of an inner function, but beware of your wording, because in Kotlin, you can also return a reference to a function

Example (you can execute it here) :

import kotlin.random.Random

fun doStuff() : String {
    fun resultIfTrue() : String { return "Returns True" }
    fun resultIfFalse() : String { return "Returns False" }
    
    return if (Random.nextBoolean()) {
        resultIfTrue()
    } else {
        resultIfFalse()
    }
}

fun deferStuff() : () -> String {
    fun resultIfTrue() : String { return "Returns True"; }
    fun resultIfFalse() : String { return "Returns False"; }
    
    return if (Random.nextBoolean()) {
        ::resultIfTrue
    } else {
        ::resultIfFalse
    }
}

fun main() {
    println("Return result of inner function")
    for (i in 0 until 4) println(doStuff())
    println("Return inner function")
    for (i in 0 until 4) {
        val fn = deferStuff()
        println("Function returned another function: $fn that must be executed: ${fn()}")
    }
}

The above snippet prints:

Return result of inner function
Returns False
Returns False
Returns True
Returns True
Return inner function
Function returned another function: function resultIfFalse (Kotlin reflection is not available) that must be executed: Returns False
Function returned another function: function resultIfFalse (Kotlin reflection is not available) that must be executed: Returns False
Function returned another function: function resultIfFalse (Kotlin reflection is not available) that must be executed: Returns False
Function returned another function: function resultIfTrue (Kotlin reflection is not available) that must be executed: Returns True

You can see that the first half of the output shows directly the values that are produced by the inner functions, because they've been called from inside doStuff directly.

However, in the second case, where we've returned the inner function itself, it needs to be called by user (here the main function) later.

Upvotes: 5

Related Questions