Blending Magnolia with Circe's trick for automatic derivation

865 views Asked by At

I've got a typeclass and want to provide semi-automatic and automatic derivation to users. I have a working implementation based on Magnolia and it works really well. There's a trait providing definitions for Typeclass[A], combine[A] and dispatch[A], then both types of derivation are accessible with

final object semiauto extends Derivation {
  def deriveFormat[A]: Typeclass[A] = macro Magnolia.gen[A]
}

final object auto extends Derivation {
  implicit def deriveFormat[A]: Typeclass[A] = macro Magnolia.gen[A]
}

Nothing surprising. Not surprising either is that when users bring auto._ into scope, it overshadows efficient derivations written for specific types.

I was hoping I could use the same technique Travis Brown devised for Circe, which basically works like this:

Define a placeholder value class that can hold on any value

case class Exported[A](instance: A) extends AnyVal

Provide a low-priority automatic derivation for my typeclass when a value of that class is in scope

object DynamoFormat extends LowPriorityDerivation {
  // derivation for specific types
  ...
}

trait LowPriorityDerivation {
  implicit def deriveExported[A](implicit e: Exported[DynamoFormat[A]]) =
    e.instance
}

Finally, hide automatic derivation of exported objects in auto

final object auto extends Derivation {
  implicit def derive[A]: Exported[DynamoFormat[A]] =
    Exported(semiauto.deriveFormat[A])
}

Sadly there's a compilation error when trying to summon the macro:

magnolia: could not infer auto.Typeclass for type com.gu.scanamo.DynamoFormat[A]
    Exported(deriveDynamoFormat[A])
                               ^

I've been looking at this code for too long now that I can't find a way out; any help would be greatly appreciated.

1

There are 1 answers

0
余杰水 On

maybe you can use a macro wrap it

object MacroWrap {

  def typeName[T]: String = macro typeNameImpl[T]

  def typeNameImpl[T: c.WeakTypeTag](c: blackbox.Context): c.universe.Tree = {
    import c.universe._
    q"${c.weakTypeOf[T].toString}"
  }

  def typeNameWeak[T]: String = macro typeNameWeakImpl[T]

  def typeNameWeakImpl[T: c.WeakTypeTag](c: blackbox.Context) = {
    import c.universe._
    q"${reify(MacroWrap)}.typeName[${weakTypeOf[T]}]"
  }
}

//test

println(MacroWrap.typeNameWeak[String]) // will print String