Interfaces

In Kotlin, interfaces and classes are public by default. There is also no implements or extends keyword in Kotlin - instead these are delineated with a :, so class A : B.

interface Time {
    fun setTime(hours: Int, mins: Int = 0, secs: Int = 0)
    fun now(): Time
}

class YetiTime : Time {
    override fun setTime(hours: Int, mins: Int, secs: Int) {}
}

When implementing a class in Kotlin, you have to use the override keyword for any functions you are duplicating from the implementation. This is to tell the compiler that you are not trying to rename the method or that it was a mistake, that you are, in fact, overriding the implementation.

Like in Java8, we can implement default methods in Kotlin.

interface Time {
...
fun later(): Time = setTime(time.hours + 1)
}

If we want to implement multiple interfaces, then we would use the format class A : B, C. In the overridden methods, we must choose which method is being implemented from one of the interfaces, such as super<B>.doSomething() {}

Actual Classes

There are some differences between Kotlin classes and Java classes. Although, under the covers they are complied to the same, when writing in Kotlin there are several syntax differences. In addition to being public by default, classes are also final by default. Methods are also final by default, so you can’t override functions unless it’s explicitly allowed. To allow a class or function to be overridden, we have to use the open keyword - open class or open fun. This forces us to look at the structure and behavior of our classes and functions. Abstract classes are open by default, but the methods inside an abstract class are still final. You could also use the abstract keyword on functions, but you would need to provide either a default implementation or a define a new one in the class it’s implemented.

Kotlin doesn’t not have package-level visibility rules like Java, so there is not a package-private setting. It does, however, have a concept of internal classes. This would limit the visibility of the class to its module. Kotlin also supports private and protected, just not package private.

Sealed Classes, or Super Enums

Besides abstract classes and modifiers, like in Java, but Kotlin also supports sealed classes. Sealed Classes are used to restrict class Hierarchies; in many ways these can be seen as “enums on steroids.” To create a sealed class, we use the sealed keyword:

sealed class Event {
    class Depart(id: Int, to: String) : Type()
    class Arrive(id: Int, from: String) : Event()
}

Only the classes defined within a sealed class can derive from that class, so this tightly controls what classes can exist within our code. Sealed classes also introduce the when statement that allows us to handle the different classes derived from the sealed class.

fun handleEvent(e:Event) =
    when(e) {
        is Depart -> print(e.to)
        is Arrive -> print(e.from)
    }

Within a when statement, there’s not an else or default available because we should know all the derived classes from the sealed class and be able to handle them. So instead of using a switch statement with enums, we can handle similar situations with a sealed class.