Interfaces

The interface keyword defines a new interface. Within the interface body you list methods that class must implement. An empty interface is allowed.

Kotlin supports methods with default implementation. Such methods are called non-abstract and can be private.

The override keyword allows you to override a method in an inherited interface or in a class that implements the interface.

An overridden method can change the return type to any subclass.

A class can implement multiple interfaces. A non-abstract class must implement all methods of the specified interfaces.

// an empty interface
interface Empty 

interface InterfaceName {
    fun foo()
    fun bar(arg: Int=56): Boolean
    fun printBar(arg: Int){println("bar is ${bar(arg)}")}
    fun newObj(): ClsA
}

interface InterfaceName2: InterfaceName, Empty {
   override fun newObj(): SubClsA
}

class Cls : InterfaceName, Empty{
    override fun foo(){ ... }
    override fun bar(arg: Int) = arg%2 == 0
    // this class uses default implementation of printBar
}

default implementation

You can override the () operator of companion object to provide default implementation.

interface Demo {
    fun foo()

    companion object {
        operator fun invoke(): Demo = DemoImpl()
    }
}

class DemoImpl : Demo {
    override fun foo() {
        // ...
    }
}
// usage: val demo = Demo()

anonymous instance

An anonymous instance of an interface can be created through an anonymous object.

interface Task {
    fun onTask(workerActions: WorkerActions)
}

var mainTask = object : Task{
            override fun onTask( workerActions: workerActions) {
                TODO("Not yet implemented")
            }
        }

functional interface

You can declare a single abstract method (SAM) interface as a functional interface with the fun keyword. This allows you to convert the interface to a lambda function and vice versa.

val task = Runnable {
    // do stuff
}
fun interface Task { fun onTask(workerActions: WorkerActions) } class Worker{ ... // methods accept interface open fun onPreProcess(task: Task): Worker{...} open fun onPostProcess(task: Task): Worker{...} open fun onMainTask(task: Task): Worker{...} } // but we can use lambdas, instead anonymous implementation val worker = Worker().onMainTask{ actions-> ... }.onPreProcess{ actions-> ... }.onPostProcess{ actions-> ... }

properties

You can add properties to the interface. This will be considered a shorthand for getter/setter methods. These properties cannot be initialized.

interface TaskData<T> {
    val data: T?
}

class MutableTaskData<T> : TaskData<T> {
    override var data: T? = null
}
interface ProgressDataInfo {
    val current: Long
    val total: Long
}

class ProgressData : ProgressDataInfo {
    var mCurrent: Long = 0
    var mTotal: Long = 0

    override val current: Long
        get() = mCurrent

    override val total: Long
        get() = mTotal
}

delegation

A class can delegate the implementation of an interface to another object.

interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

class Derived(b: Base) : Base by b

fun main() {
    val b = BaseImpl(10)
    Derived(b).print()
}

resolving overriding conflicts

When we declare many types in our supertype list, it may appear that we inherit more than one implementation of the same method.

interface A {
    fun foo() { print("A") }
    fun bar()
}

interface B {
    fun foo() { print("B") }
    fun bar() { print("bar") }
}

class D : A, B {
    override fun foo() {
        super<A>.foo() // call A implementation
        super<B>.foo() // call B implementation
    }

    override fun bar() {
        super<B>.bar() // call B implementation
    }
}