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.

Custom data types

Custom types that focus on plain data. These allow you to model the information you work with. Structure and group data, and define relationships between entities. In other languages, they may be called “structs” or “records” and may behave as value types. In Kotlin, they are reference types, same as object types, but with some limitations and advantages.

Value classes

A value/inline class is a wrapper type around a single property. It’s almost like a type alias, but actually defines a new type and supports adding methods and computed properties, and even alternative constructors. A stored property can be only one.

Note: Value classes do not translate well to Swift/Objective-C.

interface HasLength {
  fun length(): Int
}

@JvmInline
value class Username(private val username: String): HasLength {

  init {
    require(username.isValid())
  }

  val isValid: Boolean
    get() = username.isValid()

  override fun length(): Int = username.length

  companion object {
    fun String.isValid(): Boolean = isNotBlank()
  }
}

[--]