arnfred arnfred - 1 year ago 52
Scala Question

Why can't I seem to merge shapeless records with Options correctly?

If I merge two records as follows:

case object Key
val a = (Key ->> Option.empty[String]) :: HNil
val b = (Key ->> Option("plif")) :: HNil
val c = a.merge(b)

Then as we would expect we have that
b == c
. However, if I use a plain string instead of
then this isn't true anymore:

case object Key
val a = (Key ->> "pluf") :: HNil
val b = (Key ->> Option("plif")) :: HNil
val c = a.merge(b)

In this case
turns out to be:
"pluf" :: Some("plif") :: HNil
Key :: Key :: HNil
. What gives?

I'm using Shapeless 2.1 if this makes any difference.

Answer Source

I would assume that the types being merged have to be congruent to merging. That is, they must be of the same type. In the first case you have 2 Option[String] types while in the 2nd case, you have an Option[String] and a String.

Looking at the code ( and working through the implicit logic to understand how Merger works:

  1. We can see that the implicit with the highest priority ( prefers that the value types match between records. It substitutes the value in the merged record output.
  2. The lower priority implicit ( is only activated if the types don't match, appending the head and then iteratively traversing down into the record's structure.
  3. Finally, in the case of HNil it just appends whatever remains after all other operations in the second record to the first. That is, if they don't match in size, it takes whatever else is available.