0

I have designed a case class that looks superficially like this:

case class Moo(foos: Seq[Foo], bar: Bar) {
  require(foos.length == bar.baz.length)
  ...
}

This type will be consumed by a Java program, so I have created a convenient MooBuilder to make it easier to populate the fields without having to explicitly instantiate Foos, Bars, and other types contained by these.

Currently MooBuilder creates copies of objects when a field is set by its methods. I had read about lenses and wanted to give them a try to make the implementation cleaner.

So I installed quicklens and rewrote the builder, but came across this situation:

def addFooAndBaz(foo: Foo, baz: Baz): MooBuilder = {
  moo = moo
    .modify(_.foos)   .using(_ :+ foo)  /* (1) */
    .modify(_.bar.baz).using(_ :+ baz)  /* (2) */
  this
}

Immediately after (1), moo.foos has one more element than moo.bar.baz, and this makes the require call fail, so it never gets to (2) to fix the mismatch.

I know I can work around the issue by doing all the copying by hand (as I was doing before) or by removing the require call in my case class's constructor. Still, I'd like to know: is there a standard way to solve the problem of doing several updates that make sense combined but not on their own, using lenses in Scala?

Roberto Bonvallet
  • 31,943
  • 5
  • 40
  • 57
  • What if instead of using lenses, you just add a method to your `Moo` case class called `withFooAndBaz` that performs the copying? Then you can just write `moo = moo.withFooAndBaz(foo, baz)`. Using a lens is just abstracting calls to `copy` - you never actually mutate an instance of `Moo`, but instead return a new updated copy at each step. – Eric Mar 14 '17 at 17:04
  • @Eric: that's what I was doing, and it involves a lot of explicit copying (I have more nested classes than this example). I would like to know if lenses can help in an elegant way. – Roberto Bonvallet Mar 14 '17 at 17:31

0 Answers0