ProgrammatieBackend ontwikkelaar

Wat zijn inline classes (value classes) in Kotlin, waarvoor worden ze gebruikt en welke beperkingen zijn er bij het gebruik ervan?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Geschiedenis van de vraag

In Kotlin werd het concept van inline/value classes (nu value class genoemd) geïntroduceerd om de runtime-overhead bij het werken met wrappers rond primitieve types en kleine structuren te minimaliseren. Het idee is geleend uit andere talen (bijvoorbeeld C# structs), waar een dergelijke optimalisatie nuttig is voor prestatieverbetering zonder verlies van type-veiligheid.

Probleem

Het creëren van wrapper classes (bijvoorbeeld voor entity types of identifiers) zonder optimalisatie leidt tot de creatie van een extra object in het geheugen, wat de prestaties, GC beïnvloedt en kan leiden tot Boxing/Unboxing overhead. Vaak is er de wens om strikte type-veiligheid te hebben (bijvoorbeeld UserId in plaats van Int), maar zonder daadwerkelijk objecten te creëren.

Oplossing

Een value class wordt gedeclareerd met de modifier value. In de meeste situaties creëert de JVM geen extra object — de value class wordt rechtstreeks vervangen door zijn veld (inlining). Dit biedt type-veiligheid en prestaties die dicht bij "gewoon Int" liggen.

Codevoorbeeld:

@JvmInline value class UserId(val value: Int) fun showId(id: UserId) = println(id.value) val id = UserId(15) showId(id) // Zonder het creëren van een apart object UserId

Belangrijkste kenmerken:

  • De class moet precies één eigenschap (val of var) bevatten, maar dit type mag niet nullable zijn.
  • Geen ondersteuning voor overerving (value class kan niet erven of geërfd worden).
  • Enkele beperkingen: onmogelijk om een init-blok te hebben, lateinit of niet-geïnititaliseerde eigenschappen op te slaan, geen reflectie voor alle gevallen.

Vragen met een twist.

Kunnen value classes meerdere eigenschappen hebben?

Nee, value classes kunnen slechts één eigenschap bevatten.

// Fout: // value class Money(val amount: Int, val currency: String)

Kan een value class een nullable eigenschap hebben?

Het value veld in een value class kan niet nullable zijn — alleen niet-nullable types.

// Fout: // value class Name(val value: String?)

Kan overerving worden gebruikt met value classes?

Value classes ondersteunen geen overerving en kunnen niet abstract of sealed zijn.

// Fout: // value class NewId(val value: Int): BaseId()

Typische fouten en anti-patterns

  • Pogingen om value classes te gebruiken voor complexe structuren (bijvoorbeeld met meerdere velden)
  • Opslag van nullable waarden via value classes
  • Gebruik van referentiële methoden (bijvoorbeeld methods equals/hashCode kunnen zich onverwacht gedragen in de gecompileerde backend)

Voorbeeld uit het leven

Negatieve case

Een ontwikkelaar creëerde een value class voor een entiteit met twee eigenschappen (bijvoorbeeld een Int en een String), en kreeg een compilatiefout.

Voordelen:

  • Probeert strikte typing te bereiken. Nadelen:
  • Werkt niet, compilatie is niet mogelijk.

Positieve case

Een ontwikkelaar gebruikt een value class voor een type-identifier met één veld (bijvoorbeeld UserId), wat snel en veilig werkt.

Voordelen:

  • Compacte en veilige code.
  • Geen runtime-overhead. Nadelen:
  • Kan alleen worden gebruikt met één niet-nullable type.