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.

Community
  • 1
  • 1
vtor
  • 8,989
  • 7
  • 51
  • 67

3 Answers3

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.

Jayson Minard
  • 84,842
  • 38
  • 184
  • 227
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 }

Kiskae
  • 24,655
  • 2
  • 77
  • 74
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,"+"))
}
dzrkot
  • 543
  • 2
  • 4
  • 23