Search code examples
kotlinarrow-kt

Modify property of sealed interface


I'm trying to modify a property on a sealed interface. Are optics for properties of a interface not generated? Can I use some kind of Lens/Prism/Iso to access the property?

@Test
fun `Modify field on sealed interface`() {
    val orgA = SealedType.TypeA(0)

    // property [value] is not generated by optics, only `SealedType.typeA.value` exists.
    val newA = SealedType.value.modify(orgA) { it + 1}
    
    expectThat(newA.value).isEqualTo(1)
}

@optics sealed interface SealedType {
    val value: Int
    companion object;

    @optics data class TypeA(
        override val value: Int
    ) : SealedType {
        companion object
    }

    // TypeB ... same as TypeA
    
}

Do I have to manually write a Lens like this? Or can it be achieved through Prism/Iso or something else that I've missed?

companion object {
    val value: Lens<SealedType, Int> inline get() = Lens(
        get = { subject ->
            subject.value
        },
        set = { subject, newValue ->
            when (subject) {
                is TypeA -> subject.copy(value = newValue)
                is TypeB -> subject.copy(value = newValue)
            }
        }
    )
}

Solution

  • This is currently not implemented, but an issue exists for it. https://github.com/arrow-kt/arrow/issues/2829

    I'm going to prioritise this higher, because I really would love to have this functionality in Arrow Optics. I am going to try to release this in the coming month.

    Thanks for raising here again, I will report back here when it's merged and released in 1.2.2

    The current workaround is indeed to write your own optic as you've done here.