Deriving incomplete type class instances

Suppose we’ve got a simple representation of a user:

Now suppose we’re writing a web service where we allow clients to post some JSON to a resource to create a new user. We get to pick the id, not the client, so we might accept something like this:

If we’re using a type class-based JSON library like Argonaut, we’ll probably have written a codec instance for User (or we may be using a library like argonaut-shapeless that derives instances for our case classes automatically).

The problem is that our User codec won’t work on JSON like the example above (since it’s missing the id field).

One way around this issue would be to write a new case class that represents a partial user:

Or we could use a framework like metarest that would handle this boilerplate for us. It’d be nice to have a more generic solution, though. One possibility would be to have partial DecodeJson instances derived for us. In our example above, this might look like the following:

But this of course doesn’t work, since argonaut-shapeless only generates instances for things that have LabelledGeneric instances.

It is possible to make this happen, though—we just need something like this:

Note that we get all of this stuff off the shelf with Shapeless (and Scalaz, which we’re only using for its Functor) except for Complement (more about that in a minute).

Now we can write something like this:

And then:

Which is exactly what we wanted, with no boilerplate.

It also works with more complicated case classes (note the duplicate type):

Or with multiple missing pieces:

And if we really need to disambiguate missing fields with the same type, we can use labels:

And then:

And we can accomplish all of this with no new macros and about a dozen lines of code, thanks to Shapeless (if we don’t count the Complement type class, which is a very generic, slightly modified version of ops.hlist.RemoveAll).

A full demonstration project (including Complement) is available here, and a version of Incompletes may be coming to either argonaut-shapeless or Finch soon.