CodeBlanks Logo Icon CodeBlanks

Type safety

Learn type safety with value classes.

Type safety

The core purpose of a value class is type safety. UserId and OrderId both wrap a String yet they are distinct types. A declaration like fun findUser(id: UserId) makes passing an OrderId by mistake a compile error.

Using the same String type everywhere is error-prone: if a function expects both a user and an order number the compiler cannot tell which one you passed. A value class removes this risk. There is no runtime memory cost; the check happens only at compile time.

Runtime representation

A value class is represented at runtime without boxing. UserId("U1") is stored in memory simply as the String "U1"; no wrapper object is created. This gives the value class zero overhead.

Boxing can occur when a value class is assigned to an Any or added to a generic collection. In these rare cases a value class is still less overhead than a wrapper class. In most uses a value class is as fast as a String but provides type safety.

Practice Type safety with UserId and OrderId

Define @JvmInline value class UserId(val id: String) and @JvmInline value class OrderId(val id: String). Write fun findUser(id: UserId) = println("User: ${id.id}"). In main call findUser(UserId("U1")).

Starter code

Main.kt
// Define the UserId and OrderId value classes
// Write a findUser(id: UserId) method

fun main() {
    // Pass a UserId instance to findUser
}

Sample solution

Main.kt
@JvmInline
value class UserId(val id: String)
@JvmInline
value class OrderId(val id: String)

fun findUser(id: UserId) = println("User: ${id.id}")

fun main() {
    findUser(UserId("U1"))
}

Expected output

User: U1

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Complete the findUser signature

Question
fun findUser(id: ____) { /* ... */ }
Answer
fun findUser(id: UserId) { /* ... */ }

Explanation: findUser accepts only UserId.

2 Match the type safety concepts

Term Meaning
UserId vs String Distinct types
no boxing Zero overhead
compile-time Compile check
runtime Underlying type

3 Why use a value class instead of String?

  • It runs faster
  • It needs less code
  • It uses less memory
  • It provides type safety Correct answer

Explanation: A value class turns type mix-ups into compile errors.

All lessons in Intermediate