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

Enrich error message when derivation fails. #501

Closed nox213 closed 9 months ago

nox213 commented 9 months ago

We're using this pattern(#258) in our project quiet often, and I think it would be great if it provides better error message. For example,

package magnolia1.examples

import magnolia1.{Magnolia, ReadOnlyCaseClass, SealedTrait}

import scala.language.experimental.macros

trait Print[T] {
  def print(t: T): String
}

trait GenericPrint {
  type Typeclass[T] = Print[T]

  // we only have split method
  def split[T](ctx: SealedTrait[Print, T]): Print[T] = { value =>
    ctx.split(value) { sub =>
      sub.typeclass.print(sub.cast(value))
    }
  }

  implicit def gen[T]: Print[T] = macro Magnolia.gen[T]
}

sealed trait Entity
case class Person(name: String, age: Int) extends Entity
case class Place(name: String) extends Entity

object Print extends GenericPrint {
  implicit val person: Print[Person] = p => p.name + " is " + p.age
//  implicit val place: Print[Place] = _.name
  implicit val entity: Print[Entity] = gen
}

object PrintExample extends App {
  println(implicitly[Print[Entity]].print(Person("John", 32)))
  println(implicitly[Print[Entity]].print(Place("London")))
}

If we don't have an instance for Place, the current error message is the method 'join' must be defined on the derivation object Print to derive typeclasses for case classes So, it tells you that it needs join method to derive a type class instance, but it doesn't tell you which instance it was trying to derive.

With this PR, it prints, magnolia: unable to derive magnolia1.examples.Print.Typeclass[magnolia1.examples.Place] -- the method 'join' must be defined on the derivation object Print to derive typeclasses for case classes

This one tells which one it was trying to derive.

adamw commented 9 months ago

Thanks!