An inline class adds a distinct type to a value such as an amount without normally allocating a wrapper object. This prevents callers from confusing values with different meanings, such as USD cents and Japanese yen, while avoiding the repeated allocation cost of an ordinary wrapper class. section 4.5
Wrapping an expense amount
@JvmInline value class UsdCent(val amount: Int) fun addExpense(expense: UsdCent) { // save the expense as USD cent } fun main() { addExpense(UsdCent(147)) } section 4.5
The declaration and its runtime behavior work together:
- Mark the class with value and annotate it with @JvmInline. section 4.5
- Give the class exactly one primary-constructor property, which supplies the underlying representation. section 4.5
- Use the wrapper type in function signatures to make incompatible meanings harder to pass accidentally. section 4.5
- Expect the underlying type wherever possible; the wrapper must remain in some cases, notably when used as a type parameter. section 4.5
interface PrettyPrintable {
fun prettyPrint()
}
@JvmInline
value class UsdCent(val amount: Int): PrettyPrintable {
val salesTax get() = amount * 0.06
override fun prettyPrint() = println("${amount}¢")
}
fun main() {
val expense = UsdCent(1_99)
println(expense.salesTax)
// 11.94
expense.prettyPrint()
// 199¢
}
An inline class can expose computed properties and implement an interface while retaining its wrapped-value representation where possible. section 4.5
