softwaremill / magnolia

Easy, fast, transparent generic derivation of typeclass instances
https://softwaremill.com/open-source/
Apache License 2.0
764 stars 116 forks source link

special handling of AnyVal #15

Closed fommil closed 6 years ago

fommil commented 7 years ago

one of the things that always bugged me about shapeless derivation is that this sort of thing

case class Bar(underlying: String) extends AnyVal
case class Foo(bar: Bar)

would be generically derived the same way as

case class Bar(underlying: String)
case class Foo(bar: Bar)

e.g. json would look like

{ "bar": { "underlying": "blah" } }

instead of

{ "bar" : "blah" }

it would be really great if magnolia had special handling for AnyVal classes.

There is also the larger issue of refined types... but I'll leave that for another day...

fommil commented 7 years ago

FYI the shapeless handling https://github.com/circe/circe/issues/469

propensive commented 7 years ago

Oh, that's interesting. I always assumed the special handling was to avoid the "underlying" value. This is what Rapture always did (in Magnolia's earlier manifestation). Anyway, it sounds like I'm on the same page as you, and I already had the expectation of supporting AnyVals in this way.

My current focus for Magnolia is to fix the API so that derivations of the various different shapes of typeclass we want to support actually work. At the moment, it seems like every instance needs its own special case...

propensive commented 7 years ago

I have a solution for this, by the way. It just needs quasiquotes, which I'd hoped to avoid.

propensive commented 6 years ago

Using the new API, it should be easy to find a way to support AnyVals. Most likely, the best way would be to reuse the existing combine method, but add an additional method to CaseClass called isValueClass. If users wanted to treat AnyVals differently, they could branch on its value, but if not, they would work just like case classes.

propensive commented 6 years ago

I've implemented this now. By default, an AnyVal is treated exactly like a one-parameter case-class, but I've added a boolean flag on the CaseClass instance which will test whether it's really a value class. If it is, you can choose how to deal with it.