Inline value classes

Good wrap up article (with great example of the usage)

Thoughts from official Kotlin team

We can use inline value classes to make a wrapper around some type with no performance overhead (Item 47: Avoid unnecessary object creation). Two especially popular uses of inline value classes are:

  • To indicate a unit of measure.

  • To use types to protect users from value misuse.

@JvmInline
value class Name(private val value: String) {
    fun greet() {
        print("Hello, I am $value")
    }
}

// Code
val name: Name = Name("Marcin")

// During compilation replaced with code similar to:
// Such a class will be replaced with the value it holds whenever possible:
val name: String = "Marcin"

//-------------------

// Code
name.greet()

// During compilation replaced with code similar to: STATIC methods
Name.`greet-impl`(name)

JPA Entities

In SQL databases, we often identify elements by their IDs, which are all just numbers. For instance, let’s say that you have a student’s grade in a system, which will probably need to reference the id of a student, teacher, school, etc:

@Entity(tableName = "grades")
class Grades(
    @ColumnInfo(name = "studentId")
    val studentId: Int,
    @ColumnInfo(name = "teacherId")
    val teacherId: Int,
    @ColumnInfo(name = "schoolId")
    val schoolId: Int,
    // ...
)

The problem is that it is really easy to later misuse all these ids, and the type system does not protect us because they are all of type Int. The solution is to wrap all these integers into separate inline value classes:

@JvmInline
value class StudentId(val studentId: Int)

@JvmInline
value class TeacherId(val teacherId: Int)

@JvmInline
value class SchoolId(val studentId: Int)

@Entity(tableName = "grades")
class Grades(
    @ColumnInfo(name = "studentId")
    val studentId: StudentId,
    @ColumnInfo(name = "teacherId")
    val teacherId: TeacherId,
    @ColumnInfo(name = "schoolId")
    val schoolId: SchoolId,
    // ...
)

Now those id uses will be safe and the database will be generated correctly because all these types will be replaced with Int anyway during compilation. This way, inline value classes allow us to introduce types where they were not allowed before; thanks to this, we have safer code with no performance overhead.

Last updated