I can delegate to a contructor parameter in a class
class SerialNumber(val value: String) : CharSequence by value {
init {
require(value.isNotBlank())
}
}
but if I make the class a value class
@JvmInline
value class SerialNumber(val value: String) : CharSequence by value {
init {
require(value.isNotBlank())
}
}
then the compiler says "Value class cannot implement an interface by delegation if expression is not a parameter"
As far as I can see value
is a parameter - what is going on?
CodePudding user response:
Implementation by delegation for inline classes was enabled in version 1.7.0
If you want to create a lightweight wrapper for a value or class instance, it's necessary to implement all interface methods by hand. Implementation by delegation solves this issue, but it did not work with inline classes before 1.7.0. This restriction has been removed, so you can now create lightweight wrappers that do not allocate memory in most cases.
The issue is here: https://youtrack.jetbrains.com/issue/KT-27435
Before Kotlin 1.7, it is not possible to implement an interface by delegation, and you will get an error (and, as you note, a nonsensical one at that).
If you are unable to update to 1.7, you can manually delegate to the value. Thankfully Kotlin keeps its class-footprint small by utilising extension functions, so this is pretty easy! You just need to delegate one property, and two functions.
@JvmInline
value class SerialNumber(val value: String) : CharSequence {
init {
require(value.isNotBlank())
}
override val length: Int
get() = value.length
override operator fun get(index: Int): Char = value[index]
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence =
value.subSequence(startIndex, endIndex)
}