Lenses for Kotlin


#1

Inspired by Miles Sabin’s Shapeless for Scala (but considerably less complex and powerful), I’ve implemented lenses on data classes, using an extension method on KProperty1 as illustrated below:

@Test fun lensesCompose(): Unit {
    data class Inner(val value: String)
    data class Outer(val outerValue: String, val inner: Inner?)

    val foo = Outer("foo", null)

    val outerValueLens = Outer::outerValue.lens()
    val innerLens = Outer::inner.lens() orElse Inner("xyzzy")
    val valueLens = Inner::value.lens()
    val innerValueLens = innerLens + valueLens

    assertEquals("foo", outerValueLens(foo))
    assertEquals(Outer("quux", null), outerValueLens(foo, "quux"))
    assertEquals(Inner("xyzzy"), innerLens(foo))
    assertEquals(Outer("foo", Inner("frobnitz")), innerValueLens(foo, "frobnitz"))
}

@Test fun updating(): Unit {
    data class Inner(val value: Int)
    data class Outer(val outerValue: String, val inner: Inner)

    val foo = Outer("foo", Inner(23))

    val innerValueLens = Outer::inner.lens() + Inner::value.lens()

    assertEquals(Outer("foo", Inner(46)), innerValueLens(foo) { times(2) })
}

The source can be found on github, and the library downloaded from Maven Central.

One thing I dislike about this implementation is the dependency on reflection (it has to look at the parameter names in the class constructor, and assumes that they match up to the available property names). It would be great if Person::name(person, “new name”) could be made directly equivalent to person.copy(name = “new name”) without relying on this mechanism.


#2

Nice. I noticed your example on github uses +Outer::value instead of .lens() … I must say, part of scalaz’s reputation for rendering code unreadable is due to its abuse of operator overloading. I think .lens is not so bad, maybe require it rather than provide the option of using +? Also I’d resist the temptation to redefine the modulo operator, if I were you. Especially given there’s no documentation for it.

By the way, your two line explanation of lenses is infinitely better than the one provided in scalaz.