What languages ​​support lenses or a similar way to update immutable nested structures?

While immutability praised many, it was difficult for me to maintain in basic programming. In my experience, programmers will sooner or later make the fields mutable again in order to avoid refactoring a large piece of code that would have to pass the updated object along with the return value.

Scala has some support with copy constructors, but I don’t know a satisfactory solution for updating complex objects. Maybe I missed something.

The best implementation I've experimented with is a data lens in Haskell. However, Haskell is hard to learn. What are the options for popular cross-platform programming languages ​​such as Java or Scala?

+8
java immutability scala lenses
source share
2 answers

In fact, there is no need for language support for the lenses - although, of course, they can be more or less useful depending on the properties of the language, and the clarity of the syntax will depend on the features of the language.

As I mentioned above, there are good lens libraries for Scala, although the language itself does not (and probably should not) provide them. For example, suppose we have the following classes:

case class Email(user: String, domain: String) case class Contact(email: Email, web: String) case class Person(name: String, contact: Contact) 

And instance:

 val foo = Person( "Foo McBar", Contact(Email("foo", "mcbar.com"), "http://mcbar.com/foo") ) 

Using Shapeless , you can write the following (note that in the next version 2.0 you will not need an isolator template):

 import shapeless._, Nat._ implicit val emailIso = Iso.hlist(Email.apply _, Email.unapply _) implicit val contactIso = Iso.hlist(Contact.apply _, Contact.unapply _) implicit val personIso = Iso.hlist(Person.apply _, Person.unapply _) 

And then:

 val emailDomainLens = Lens[Contact] >> _1 >> _1 

And now Foo McBar can easily change its email domain:

 scala> println(emailHostLens.set(foo)("mcbar.org")) Person(Foo McBar,Contact(Email(foo,mcbar.com),mcbar.org)) 

This is all Scala vanilla - the current version of Shapeless (1.2.4) does not use macros or compiler plugins, etc., and will work on Scala 2.9. If we want to use Scala 2.10 macros, we get even more pleasant syntax and fewer templates:

 scala> import rillit._ import rillit._ scala> println(Lenser[Person].contact.email.domain.set(foo)("mcbar.org")) Person(Foo McBar,Contact(Email(foo,mcbar.org),http://mcbar.com/foo)) 

It uses Rillit , a proof-of-concept lens library developed by Aki Saarinen (and later adapted by me ).

All this could be done in Java, although the syntax is unlikely to be as clean. In fact, I'm sure Java lens libraries exist, although I have never seen or used them, and the relative lack of attention to immutable data types means that most Java developers will never need or need a lens.

+7
source share

There are lenses in Octarine that are used to create record keys to create paths in data structures:

 Record testRecord = $$( name.of("Arthur Putey"), age.of(43), address.of( addressLines.of("23 Acacia Avenue", "Sunderland", "VB6 5UX") ) ); Lens<Record, String> secondLineOfAddress = address.assertPresent() .join(addressLines.assertPresent()) .join(Lens.intoPVector(1)); assertThat(secondLineOfAddress.get(testRecord), equalTo("Sunderland")); assertThat(secondLineOfAddress.set(testRecord, "Cirencester"), equalTo($$( name.of("Arthur Putey"), age.of(43), address.of(Record.of( addressLines.of("23 Acacia Avenue", "Cirencester", "VB6 5UX") )) ))); 
0
source share

All Articles