TL;DR: Quicklens: modify deeply nested fields in case classes, e.g.:

modify(person)(_.address.street.name).using(_.toUpperCase) .

Similar to lenses, but without the actual lens creation.

Lenses are very useful when you have to update a deeply nested field in a hierarchy of case classes. For example if we have:

1 2 3 4 5 case class Street ( name : String ) case class Address ( street : Street ) case class Person ( address : Address ) val person = Person ( Address ( Street ( "1 Functional Rd." ) ) ) case class Street(name: String) case class Address(street: Street) case class Person(address: Address) val person = Person(Address(Street("1 Functional Rd.")))

and we’d like to modify the name of the street (let’s say convert to upper case), we would have to do:

1 2 3 4 5 6 7 person. copy ( address = person. address . copy ( street = person. address . street . copy ( name = person. address . street . name . toUpperCase ) ) ) person.copy( address = person.address.copy( street = person.address.street.copy( name = person.address.street.name.toUpperCase ) ) )

Quite a lot of boilerplate! Plus it’s quite hard to see what we are actually trying to achieve.

One solution is to use lenses and lens composition, which provide a much shorter way to achieve the above. There’s a couple of lens libraries, e.g. Monocle; using it, our example now becomes:

1 2 3 4 5 val _ name = Lenser [ Street ] ( _ . name ) val _ street = Lenser [ Address ] ( _ . address ) val _ address = Lenser [ Person ] ( _ . person ) ( _ address ^|- > _ street ^|- > _ name ) . modify ( _ . toUpperCase ) ( person ) val _name = Lenser[Street](_.name) val _street = Lenser[Address](_.address) val _address = Lenser[Person](_.person) (_address ^|-> _street ^|-> _name).modify(_.toUpperCase)(person)

Lenses can be also created using macro annotations, however that’s IDE-unfriendly. The lens objects ( _name , _street , _address ) provide a view into a specific field of a case class, and can be composed with each other (plus a couple of extra things!).

What if we just want to update a field? The process of creating the lens objects can then become boilerplate as well.

Using the Quicklens macro we can simplify the original task to:

1 modify ( person ) ( _ . address . street . name ) . using ( _ . toUpperCase ) modify(person)(_.address.street.name).using(_.toUpperCase)

As modify is a macro, this code is transformed during compile time into the appropriate chain of “copy” invocations (no intermediate objects or actual lenses are created); hence the bytecode is almost identical to the original, “boilerplate” solution.

I think Quicklens can be a good alternative for lens creation if you need just the field updates, without the additional features of full-blown lenses. I’m also not aware of a similar existing implementation. Quicklens is open-source and available on Github under the Apache2 license. Comments welcome!