Reputation: 1681
I've just started learning Kotlin and I'm having a problem with lambdas syntax there. There is a small example class:
class MathFunctions {
@FunctionalInterface
interface Operation {
fun calculate(a: Int, b: Int): Int
}
fun makeCalculations(a: Int, b: Int, operation: Operation): Int = operation.calculate(a, b)
companion object {
@JvmStatic
fun main(args: Array<String>) {
val plus = Operation { a, b -> a + b }
val mathFunctions = MathFunctions()
println(mathFunctions.makeCalculations(10, 20, plus))
}
}
}
The class never compiles because something is wrong with lambda. The same in Java looks like this:
public class MathFunctions {
@FunctionalInterface
interface Operation {
int calculate(int a, int b);
}
public int makeCalculations(int a, int b, Operation operation) {
return operation.calculate(a, b);
}
public static void main(String[] args) {
Operation plus = (a, b) -> a + b;
MathFunctions example = new MathFunctions();
System.out.println(example.makeCalculations(10, 20, plus));
}
}
What should be corrected? I've already tried automatic conversion from Java into Kotlin in Intellij Idea and it failed.
Upvotes: 3
Views: 92
Reputation: 10605
Kotlin does not (yet) support SAM Functional Interfaces for Kotlin Interfaces. It only supports SAM for Java Interfaces. Reasons have been described elsewhere. But, because the SAM paradigm is ubiquitous in Java, and because Kotlin adopters are typically converting Java to Kotlin, and because SAM exists in much of that code to be ported, it is possible that they will start supporting SAM on Kotlin interfaces.
The answer (for now) is to use a object literal where a lambda conversion would be hoped for.
println(mathFunctions.makeCalculations(10, 20, object : Operation {
override fun calculate(a:Int, b:Int):Int {
return a+b
}
}))
Here is a discussion on supporting the feature.
Upvotes: 1
Reputation: 147951
The problem with your code is that Kotlin does not allow SAM conversion to interfaces written in Kotlin. The reason for this restriction is that Kotlin has functional types built into the language, and one should use them instead (or fall back to anonymous object expressions).
You could rewrite your code to:
class MathFunctions {
fun makeCalculations(a: Int, b: Int, operation: (Int, Int) -> Int): Int =
operation(a, b)
companion object {
@JvmStatic
fun main(args: Array<String>) {
val plus: (Int, Int) -> Int = { a, b -> a + b }
val mathFunctions = MathFunctions()
println(mathFunctions.makeCalculations(10, 20, plus))
}
}
}
To make the code more readable, you can use type aliases:
typealias Operation = (Int, Int) -> Int
Upvotes: 3
Reputation: 12167
If you strictly want to translate the java code to kotlin, the answer is:
fun main(args: Array<String>) {
val plus = object : MathFunctions.Operation {
override fun calculate(a: Int, b: Int) = a + b
}
val mathFunctions = MathFunctions()
println(mathFunctions.makeCalculations(10, 20, plus))
}
class MathFunctions {
@FunctionalInterface
interface Operation {
fun calculate(a: Int, b: Int): Int
}
fun makeCalculations(a: Int, b: Int, operation: Operation): Int = operation.calculate(a, b)
}
But if you have a choice, maybe you prefer the following way by keeping the operation not as interface bat just as lambda parameter:
fun main(args: Array<String>) {
val mathFunctions = MathFunctions()
println(mathFunctions.makeCalculations(10, 20, { a, b -> a + b}))
}
class MathFunctions {
fun makeCalculations(a: Int, b: Int, operation: (Int, Int) -> Int): Int = operation(a, b)
}
Upvotes: 2