I'm thinking of doing something similar to Safely copying fields between case classes of different types but with reordered fields, i.e.
case class A(foo: Int, bar: Int)
case class B(bar: Int, foo: Int)
And I'd like to have something to turn a A(3, 4)
into a B(4, 3)
- shapeless' LabelledGeneric
comes to mind, however
LabelledGeneric[B].from(LabelledGeneric[A].to(A(12, 13)))
results in
<console>:15: error: type mismatch;
found : shapeless.::[shapeless.record.FieldType[shapeless.tag.@@[Symbol,String("foo")],Int],shapeless.::[shapeless.record.FieldType[shapeless.tag.@@[Symbol,String("bar")],Int],shapeless.HNil]]
(which expands to) shapeless.::[Int with shapeless.record.KeyTag[Symbol with shapeless.tag.Tagged[String("foo")],Int],shapeless.::[Int with shapeless.record.KeyTag[Symbol with shapeless.tag.Tagged[String("bar")],Int],shapeless.HNil]]
required: shapeless.::[shapeless.record.FieldType[shapeless.tag.@@[Symbol,String("bar")],Int],shapeless.::[shapeless.record.FieldType[shapeless.tag.@@[Symbol,String("foo")],Int],shapeless.HNil]]
(which expands to) shapeless.::[Int with shapeless.record.KeyTag[Symbol with shapeless.tag.Tagged[String("bar")],Int],shapeless.::[Int with shapeless.record.KeyTag[Symbol with shapeless.tag.Tagged[String("foo")],Int],shapeless.HNil]]
LabelledGeneric[B].from(LabelledGeneric[A].to(A(12, 13)))
^
How do I reorder the fields in the record (?) so this can work with a minimum of boilerplate?
I should leave this for Miles but it's happy hour where I'm from and I can't resist. As he points out in a comment above, the key is
ops.hlist.Align
, which will work just fine for records (which are just special hlists, after all).If you want a nice syntax, you need to use a trick like the following for separating the type parameter list with the target (which you want to provide explicitly) from the type parameter list with all the other stuff (which you want to be inferred):
And then:
And then:
Note that finding alignment instances will get expensive at compile time for large case classes.