typelevel / algebra

Experimental project to lay out basic algebra type classes
https://typelevel.org/algebra/
Other
378 stars 69 forks source link

Clarify usage of Eq with case objects and trait #49

Closed ms-tg closed 8 years ago

ms-tg commented 9 years ago

Hi all, I just came to this project after reading Eugene Yokota's intro to Cats' Eq typeclass, which was linked from this week's Scala Times.

I was wondering if that page could be improved by asking you folks:

  1. Is there a better way to use Eq directly with a sealed trait and case objects, which doesn't require the boiler plate in that article?
  2. Do you have a comment on the mixing of Equality and Equivalence that he brings up?

Thanks for any attention to these questions, -Marc

/cc @eed3si9n

johnynek commented 9 years ago

You may be able to make a macro that provides Eq instances for the subclasses of a sealed trait assuming only case class/object subclasses, but I'm not 100% you have that information in a macro (I've wanted to do similar things, but I have not actually looked for the macro APIs to get this done).

jcoveney commented 9 years ago

You can definitely do it with reflection

object Base { private[this] val ru = scala.reflect.runtime.universe private[this] val m = ru.runtimeMirror(getClass.getClassLoader) private[this] def sealedDescendants[Root: ru.TypeTag]: Option[Set[ru.Symbol]] = { val symbol = ru.typeOf[Root].typeSymbol val internal = symbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol] if (internal.isSealed)

Some(internal.sealedDescendants.map(_.asInstanceOf[ru.Symbol]) - symbol) else None }

def parse(str: String): Option[Base] =
    sealedDescendants[Base].flatMap {
        _.map { sym =>
          val clazz = sym.asClass

m.reflectClass(clazz).reflectConstructor(clazz.primaryConstructor.asMethod).apply().asInstanceOf[Base] }.find { _.name == str } } } sealed abstract class Base(val name: String) case object A extends Base("A") case object B extends Base("B")

Which leads me to believe you can do it in a macro (note the sealedDescendants call, which seems key)

2015-05-07 14:33 GMT-04:00 P. Oscar Boykin notifications@github.com:

You may be able to make a macro that provides Eq instances for the subclasses of a sealed trait assuming only case class/object subclasses, but I'm not 100% you have that information in a macro (I've wanted to do similar things, but I have not actually looked for the macro APIs to get this done).

— Reply to this email directly or view it on GitHub https://github.com/non/algebra/issues/49#issuecomment-99970298.