8

I've the following function in Kotlin

fun evaluate(first:Int?, second:Int?) {
    var result = 0
    if (v.equals('*')) {
        result = (first ?: 0) * (second ?: 0)
    } else if (v.equals('+')) {
        result = (first ?: 0) + (second ?: 0)
    } else if (v.equals('-')) {
        result = (first ?: 0) - (second ?: 0)
    } else if (v.equals('/')) {
        result = (first ?: 0) / (second ?: 0)
    }
    return result   
}

I want to change it in a way so that I can pass as a third parameter needed operator and evalute the expression. Something like

fun evaluate(first:Int?, second:Int?, op: () -> Unit):Int {
    return (first ?: 0).op(second ?: 0)
}

How can I pass the operator as a function in this case? I checked the same kind of a question, but it is not clear how you can do that with operator.

2
  • Do you want to get rid of if-conditions? Where does the 'v' come from? Commented Sep 13, 2016 at 12:36
  • @ilya.dorofeev hhe shows the final intended function that gets rid of all the if conditions. Commented Sep 13, 2016 at 12:55

3 Answers 3

12

Writing a higher order function using a function type as a parameter allows using both built-in operators and lambda expressions for the operation, so this would look like:

fun evaluate(first: Int?, second: Int?, op: (Int, Int) -> Int): Int {
    return op(first ?: 0, second ?: 0)
} 

Which can be called with built-in operators such as:

val r1 = evaluate(value1, value2, Int::times) 
val r2 = evaluate(value1, value2, Int::plus)
val r3 = evaluate(value1, value2, Int::minus) 
val r4 = evaluate(value1, value2, Int::div) 

And with custom functions:

val r5 = evaluate(value1, value2) { a, b -> (a * a) + b }

Now you can also assign the operators to variables, such as you v:

val v: (Int, Int)->Int = Int::times  // typing needed on left to avoid ambiguous alternatives
// and then later...
val r6 = evaluate(value1, value2, v) 

Note that a function written for signature Int.(Int)->Int can be passed into a parameter expecting (Int, Int)->Int because the receiver this will be passed in as the first parameter.

Sign up to request clarification or add additional context in comments.

4 Comments

This works as well: evaluate2(value1, value2, Int::times), so you don't need a separate function, just the last one
Interesting that the signature doesn't match, but because of the receiver being the first parameter it still works. cool. Is that intentional or a bug?
confirmed it is intentional, wil update answer, thanks @voddan
It was a pre 1.0 feature)
1

Change () -> Unit into Int.(Int) -> Int. Then all the other code should work as you've written it there.

On the calling side it this is the first int, and the first parameter is the second int: { other -> this * other }

Comments

0

you can try do that:

fun evaluate(first: Int?, second: Int? , v:String ): Int = v.op(first ?: 0, second ?: 0)

fun String.op(first:Int,second:Int):Int = when (this) {
    "*" -> first * second
    "+" -> first + second
//....
    else -> throw Exception()
}       
fun main(args: Array<String>) {
    println(evaluate(2,3,"*"))
    println(evaluate(2,3,"+"))
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.