I know about lenses and monocles, but they are too verbose and containing many of boilerplate. Because there is no support for deep copy (for case-classes, at least) on language level, this way, even macros can’t help to make immutable programming such concise as mutable one.
The problem is, we can read “through point” from case-classes, but cannot write.
For example, if we have a hierarchy…
case class A ( x: Int )
case class B ( s: String )
case class C ( a: A, b: Seq[B] )
Even with Scala 3 and Monocle library everyone has to write something like.
val newC = c.focus( _.b.index(someN).s ).replace("new string")
And for mapping values or so it is even harder.
My proposal is to add deep copy syntax on Scala language level. It is logical, because Scala emphasizes immutable values.
How it should work?
Code like…
val newC = c.{ a.x = 10 }
…should be transformed by compiler to copying all case-classes hierarchy with values in braces changed. In this example…
val newC = c.{ a.x = 10 }
…should be the same as…
val newC = c.a.{ x = 10 }
…because no other values changed.
But we should be able to change several values at one time.
val newC = c.{ a.x = 10, b = myCreateListFunction(someParamsInContext) }
It is similar to “copy” method already does, but “goes deeper”. We consider, that all is written inside braces after point are done not with this instance, but with its deep copy. This way, some can write…
val newC = c.{ b(someN).s = "new string" }
…and get “c” instance deep copy with “c.b” seq copy in which “someN” element replaced by “new string”.
(for this to work, it is needed to make compiler to translate “b(someN).s = x”
to “b.updated( someN, B( s = x ) )” for immutable sequences)
With this syntax addition all Scala’s default library methods will be supported automatically. For example,
val newC = c.{ b.map("my " + _.x) }
If something like this syntax will be added, immutable programming will become much easier and much more readable.