Kotlin DDD Phantom type
I was on twitter and got suggestion to read post-introduction about phantom type by Vincent Pradeilles. The idea is a code safety improvement with a minimum boilerplate and performance penalty.
The Kotlin equivalent would be next. Let’s pretend that you have code:
data class User(val id: String)
data class Address(val id: String)
val me = User(id = "test id")
val home = Address(id = "test id")
if (me.id == home.id) {
assert("Wrong! Person can not be address")
}
Isuru Rajapakse came with the next improvement:
@JvmInline value class UserId(val value: String)
@JvmInline value class AddressId(val value: String)
data class User(val id: UserId)
data class Address(val id: AddressId)
val me = User(id = UserId("test id"))
val home = Address(id = AddressId("test id"))
if (me.id == home.id) {} // This will not compile
That has minimum performance penalty but still require some boilerplate code writing.
Then Ivan Canet proposed an improvement that will require also minimum boilerplate and will be 100% equivalent to the swift code:
@JvmInline value class Id<out T>(val value: String)
data class User(val id: Id<User>)
data class Address(val id: Id<Address>)
val me = User(id = Id("test id"))
val home = Address(id = Id("test id"))
if (me.id == home.id) {} // This will not compile also
That is neat!
This code works only with Kotlin JVM backend (JVM and Android) and Kotlin version 1.7.20+
Read more about:
- Kotlin inline value classes at the official documentation
- Kotlin generic inline classes at the baeldung.com
- Kotlin generics at the official documentation
- Kotlin generics covariance and contravariance article by mvndy
- Brilliant articles about Kotlin generics by Dave Leeds — covariance and contravariance plus kotlin ins and outs