Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I omit the interface methods I do not use in Kotlin?

Tags:

kotlin

What if I am only interested in onSee and do not care for other events? Can I at least omit the methods that have no return values?

interface EventHandler
{
    fun onSee()
    fun onHear()
    fun onSmell()
    fun onTouch()
    fun onAwake()
    fun onSleep()
}

fun addEventHandler(handler:EventHandler)
{

}

fun Main()
{
    addEventHandler(object:EventHandler
    {
        override fun onSee()
        {
            print("I see.")
        }
    })
}
like image 789
Damn Vegetables Avatar asked Nov 18 '17 04:11

Damn Vegetables


People also ask

Is it mandatory to implement all the methods of an interface?

Yes, it is mandatory to implement all the methods in a class that implements an interface until and unless that class is declared as an abstract class. Implement every method defined by the interface.

How can we avoid implementing all methods interface?

However, you can avoid this by following the below approach: Declare the missing methods abstract in your class. This forces you to declare your class abstract and, as a result, forces you to subclass the class (and implement the missing methods) before you can create any objects.

Do you have to override interface methods?

If you have default method in an interface, it is not mandatory to override (provide body) it in the classes that are already implementing this interface. In short, you can access the default methods of an interface using the objects of the implementing classes.

Can an interface have no method?

Yes, you can write an interface without any methods. These are known as marking interfaces or, tagging interfaces. A marker interface i.e. it does not contain any methods or fields by implementing these interfaces a class will exhibit a special behavior with respect to the interface implemented.


2 Answers

Sure, that is possible! you can implement one interface method when you extend it, all you have to do is to provide a default implementation for the other methods in the interface declaration

interface EventHandler {
    fun onSee()
    fun onHear() { /* default implementation */ }
    fun onSmell(){ /* default implementation */ }
    fun onTouch(){ /* default implementation */ }
    fun onAwake(){ /* default implementation */ }
    fun onSleep(){ /* default implementation */ }
}

Now when you create an instance of this interface you only need to provide a compulsory implementation for onSee() method, rest are optional

If you're not the author of the original interface You could extend the original interface and provide a default implementation for the methods you want

interface OnSeeEventHandler: EventHandler {
    override fun onHear() { /* default implementation */ }
    override fun onSmell(){ /* default implementation */ }
    override fun onTouch(){ /* default implementation */ }
    override fun onAwake(){ /* default implementation */ }
    override fun onSleep(){ /* default implementation */ }
}

And use the OnSeeEventHandler to provide only onSee method imeplementation

like image 195
Samuel Robert Avatar answered Oct 12 '22 16:10

Samuel Robert


I came up with the following, somewhat p̶e̶r̶v̶e̶r̶s̶e̶ interesting approach.

The function below uses a dynamic proxy to "materialize" an interface and patch it with only the needed methods. Methods that are not patched will just return null or Unit, depending on the return type.

import java.lang.reflect.Proxy.newProxyInstance

inline fun <reified T> Any.materialize(): T = materialize(T::class.java, this)

fun <T> materialize(i: Class<T>, x: Any = object {}): T {
    @Suppress("UNCHECKED_CAST")
    return newProxyInstance(i.classLoader, arrayOf(i)) { _, m, args ->
        x.javaClass.methods
                .asSequence()
                .filter {
                    it.name == m.name
                            && it.parameterTypes!!.contentEquals(m.parameterTypes)
                }
                .map {
                    it.invoke(x, *args.orEmpty())
                }.firstOrNull()
    } as T
}

It can then be used as follow, given an interface Foo and an anonymous object that contains only an implementation of its qux() function:

interface Foo {
    fun bar()
    fun baz(): String
    fun qux(s: String): String
}

fun main(vararg args: String) {
    val foo = object {
        fun qux(s: String): String {
            return "Returned from qux: $s"
        }
    }.materialize<Foo>()

    println(foo.bar()) // void no-op, prints "kotlin.Unit"
    println(foo.baz()) // no-op with return value, prints "null"
    println(foo.qux("Hello")) // prints "Returned from qux: Hello"

}

Disclaimer

  • Using this, you lose all compile-time checking as everything is resolved at runtime.
  • Some things are not covered by this implementation (e.g. interface default methods).
  • Performance is not taken into account at all.
  • Requires the kotlin-reflect dependency.
  • Today is my second day learning Kotlin, so there might be any number of unaddressed edge cases and bugs.

I would not use this myself in most cases, and will continue to hold out for a Kotlin construct that supports partial interface implementations (like TypeScript's Partial<T>).

I'm only providing this approach because it might be of interest for some use cases, and I'm sorry if this made your eyes bleed.

like image 24
Robby Cornelissen Avatar answered Oct 12 '22 18:10

Robby Cornelissen