Everything else is just a tool to model your domain in a way that’s easier to read and reason about, and to produce much shorter code. Interfaces define module boundaries and can be mocked to enable simpler testing. Through classes, objects, and data structures, you can model your domain entities. Enums make a list of limited options crystal clear. Extensions allow you to add functionality to existing types, without having access to their original source code, giving advantage of better logic structure. With generics, you can write universal code, promoting reuse. And overloaded operators give that extra edge to common operations that benefit from succinct, crisp syntax.
Extensions
It is possible to extend functionality of existing types without resorting to inheritance. It is also possible to program standard, reusable functionality using delegation.
Delegation
It is possible to implement an interface by delegating to another object that already implements it. In other words, to proxy to another object without much boilerplate.
interface SupportsParking {
fun park(): Int
fun pay(slot: Int): Double
fun collect(slot: Int)
}
class Valet: SupportsParking {
private val parkingLot = mutableSetOf<Int>()
override fun park(): Int = 42.also { parkingLot.add(it) }
override fun pay(slot: Int): Double = 5.0
override fun collect(slot: Int) {
parkingLot.remove(slot)
}
}
class Car(cousin: Valet): SupportsParking by cousin {
override fun pay(slot: Int): Double = 0.0
}
val car = Car(cousin = Valet())
with(car) {
val slot = park().also { pay(it) }
collect(slot)
}