Why?

One key use case for this will be with object-relational mapping engines (ORMs) and similar systems, for helping to avoid “stringly-typed” properties.

Suppose, for example, that we have a database that has invoices, where invoices have a series of line items representing the things to appear on the invoice. In Kotlin, we might have Invoice and InvoiceLineItem classes to map to the tables in our database. And those classes might have properties that line up with the columns in the table… using data types based on the column types:

data class Invoice(
  val key: String,
  val createdOn: Instant,
  val customerKey: String,
  // TODO other properties
)

data class InvoiceLineItem(
  val key: String,
  val quantity: Int,
  val productKey: String,
  // TODO other properties
)

The problem here is that all of our keys are String properties:

From Kotlin’s standpoint, a String is a String is a String. We as developers know that we cannot use an InvoiceLineItem key to look up a product… but Kotlin does not know that, so it cannot enforce such a restriction. This sort of “stringly-typed” set of properties leads to bugs, where we accidentally use one class’ key where we meant another class’ key, and Kotlin lets it happen because they are all strings.

With inline class, we can wrap those strings in classes that are distinct:

data class Invoice(
  val key: InvoiceKey,
  val createdOn: Instant,
  val customerKey: CustomerKey,
  // TODO other properties
)

data class InvoiceLineItem(
  val key: InvoiceLineItemKey,
  val quantity: Int,
  val productKey: ProductKey,
  // TODO other properties
)

Each of those ...Key classes is an inline class akin to the one shown earlier in this chapter:

inline class InvoiceLineItemKey(val key: String)

At compile time, Kotlin treats all four of those ...Key classes as being distinct and not equivalent. We cannot accidentally use a ProductKey where we need an InvoiceKey, for example. This eliminates a class of bugs through strong type checking in the compilation process.

However, because they are inline class, at runtime, they are just strings. We do not incur overhead of creating instances of all of these ...Key classes. So, we gain the power of type checking without paying a price when our app runs.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.