warownia1
warownia1

Reputation: 2925

Anonymous interface instance as interface property in Kotlin

I started learning Kotlin recently and I'd like to implement a simple postfix notation parser were instances of MathOperator interface pick values from the stack and return the result. The implementation is trivial in plain Java

public interface MathOperator {
  public float evaluate(Deque<Float> stack);

  public MathOperator ADD = stack -> stack.pop() + stack.pop();
  public MathOperator SUB = stack -> -stack.pop() + stack.pop();
  public MathOperator MUL = stack -> stack.pop() * stack.pop();
}

However, when I try the same in Kotlin I get "Property getter or setter expected" error.

interface KTMathOperator {
  fun evaluate(stack: Deque<Float>): Float

  companion object {
    val ADD: KTMathOperator = (stack) -> stack.pop() + stack.pop()
  }
}

How can I implement the same interface and its properties in Kotlin concisely?

Upvotes: 1

Views: 168

Answers (1)

Andrei Tanana
Andrei Tanana

Reputation: 8422

Unfortunately, in Kotlin SAM conversions are not so handy. You can rewrite your example like:

interface KTMathOperator {
    fun evaluate(stack: Deque<Float>): Float

    companion object {
        val ADD: KTMathOperator = object : KTMathOperator {
            override fun evaluate(stack: Deque<Float>): Float = stack.pop() + stack.pop()
        }
    }
}

also you can change evaluate to invoke. Then you can your ADD just like ADD(stack)

interface KTMathOperator {
    operator fun invoke(stack: Deque<Float>): Float

    companion object {
        val ADD: KTMathOperator = object : KTMathOperator {
            override fun invoke(stack: Deque<Float>): Float = stack.pop() + stack.pop()
        }
    }
}

fun main() {
    val list = LinkedList<Float>().apply {
        add(1.0f)
        add(1.0f)
    }
    println(KTMathOperator.ADD(list)) // will print 2.0
}

If you're not too worried about maximum performance and a little strange code, you can also write like this :)

class KTMathOperator(private val operation: (Deque<Float>) -> Float) : (Deque<Float>) -> Float {
    override fun invoke(stack: Deque<Float>): Float = operation(stack)

    companion object {
        val ADD: KTMathOperator = KTMathOperator { stack -> stack.pop() + stack.pop() }
    }
}

Upvotes: 3

Related Questions