How to have a constant (computed/cached) value in ...
# getting-started
d
How to have a constant (computed/cached) value in an interface? Well, that's not my use case directly and I know that interface properties cannot have backing fields. (Also, I remember seeing a hackish workaround for that...). My intention actually is to have this computed constant in an enum class inhering from that interface. Currently, I have this
Copy code
interface CellMapping {
        val sheetAddress: String

        val cellAddress: CellAddress
            get() = CellAddress(sheetAddress)
    }

    private enum class Cells(
        override val sheetAddress: String,
        override val sheetType: SheetType,
    ) : CellMapping
This works but the CellAddress is constructed every time the
cellAddress
prop is accessed. Is there any way to avoid that?
c
Unfortunately, no. Interfaces cannot have any backing properties, and the only way to cache that value would be for the interface itself to have a property to hold the cached value. You’ll need to manually override
cellAddress
. Typically, you would address this by using an abstract or open class instead of interface, but enums cannot extend other classes so that doesn’t work here.
d
enums cannot extend other classes
Yeah, forgot to add this (known) detail. Btw what is the reason for that?
d
It's because of JVM specification. On JVM each enum class should be inherited from
java.langEnum
, and it's not allowed for class to have several super classes
👍 1
a
maybe use a sealed interface with regular classes as subtypes instead of an enum?
e
Copy code
enum class Cells(
    override val sheetAddress: String,
) : CellMapping {
    override val cellAddress by lazy {
        CellAddress(sheetAddress)
    }
}
c
Depending on how often you need to implement the interface and what’s in it, it may be worth setting up a delegate. It can add a fair amount of boilerplate, but for many computed properties, or where it’s implemented by many different classes, it can save you a lot more boilerplate, and help make sure things are done consistently (while also allowing individual classes to override if it needed)
Copy code
interface CellMapping {
    val sheetAddress: String
    val cellAddress: CellAddress
}
class CellMappingDelegate(
    override val sheetAddress: String
) : CellMapping {
    override val cellAddress: CellAddress = CellAddress(sheetAddress)
}

private enum class Cells(
    sheetAddress: String,
) : CellMapping by CellMappingDelegate(sheetAddress)
d
This is a nice workaround! I will need to think about it more, though, whether the introduced boilerplate is worth it.