quicklens
quicklens copied to clipboard
Setting nested Options to Some(value)
Hi,
Given a nested chain of Option
s, is there a way to coerce the most inner one to Some
?
The current operator .each
allows traversing Option
s, but acts like map
:
import com.softwaremill.quicklens._
case class C(d: Option[Int])
case class B(c: Option[C])
case class A(b: Option[B])
val a = A(b = None)
a.modify(_.b.each.c.each.d.each).setTo(3) // res0: A = A(None)
(the result is A(None)
, but how can we achieve a A(Some(B(Some(C(Some(3))))))
?)
It could be useful if there were some operator (say, all
) which can act as follows:
a.modify(_.b.all.c.all.d.all).setTo(3) // res0: A = A(Some(B(Some(C(Some(3))))))
I'm afraid this is very option-chain-specific. Firstly, you wouldn't be able to use .modify
, as there need not be a value. Secondly, if e.g. B
had any other fields, there's nowhere to get their values from.
What about a variation of at(idx: Int)
which doesn't throw IndexOutOfBoundsException
, and instead enlarges the sequence so accommodate the new index? Such a method could also be adapted to Option
s if we look at them as sequences if length 1.
But what would you put in the indicies in between? Also, how would you initialize an "empty" object which would be added to the sequence?
Maybe a type class Zeroable[A]
with default implementations for all the primitives?
A completely alternative solution would be a withHead[A](a: A)
which can work for all sequences (including Option
, Either
, etc.)
Maybe Zeroable
would work ... but I have the feeling that this takes the .each
syntax a bit too far. Wouldn't, in such situations, just writing code in .setTo
with the appropriate new instance creation logic be sufficient?
Yeah, on a second thought, there's no much difference between .setTo
and my suggestion.
I guess you're right :)