wix-incubator / accord

Accord: A sane validation library for Scala
http://wix.github.io/accord/
Other
529 stars 55 forks source link

Validator macro does not support Shapeless Coproduct #102

Open ALPSMAC opened 7 years ago

ALPSMAC commented 7 years ago

It's probably a stretch to expect something like Shapeless to play well with Accord, but using Coproducts and HLists within your data types can lead to a more expressive domain model. I'd love to see Accord support some limited set of functionality on Coproducts/HLists. For instance, I'd really love to do something like this:

import shapeless._
import com.wix.accord._
import com.wix.accord.dsl._

object Main{
  case class A(a: String)
  case class B(b: String)

  type AB = A :+: B :+: CNil

  implicit val aValidator: Validator[A] = ???
  implicit val bValidator: Validator[B] = ???

  implicit val abValidator: Validator[AB] = validator[AB]{ ab => 
    ab.select[A] match {
      case a if a.isInstanceOf[A] => ab.select[A].get is valid[A]
    }
    ab.select[B] match {
      case b if b.isInstanceOf[B] => ab.select[B].get is valid[B]
    }
  }
}

I would have expected this match statement in the abValidator to compile, but instead I just get a cryptic coproduct is not an enclosing class error from the compiler. My guess is the match statement isn't being processed properly by the macro(s) in Accord, although I must admit I haven't dug too deeply yet to verify.

holograph commented 7 years ago

I would actually expect this code (convoluted though it may be :-)) to work. I'll need to do some digging to find out where the "enclosing class" error originates, but an off-the-cuff guess would be that Shapeless uses macros to derive some of the requisite type classes, and Accord doesn't handle the nested macros very well.

ALPSMAC commented 7 years ago

I can certainly believe that two separate libraries both doing macro magic might conflict with each other. I can't claim that I'm an expert in Scala macros, but it seems reasonable to suspect that perhaps something Shapeless does to transform the code has caused the validator macro to behave in unexpected ways.

For now I have just used Scala's native 'Either' type to support my use case (since I am only faced with two different options for my coproduct in question at the moment).

I don't think this is so much a bug with Accord as it is an oddity with Shapeless... hopefully whatever evolution Scala Macros take in the future will better support this sort of macro library combination scenario, although I must admit that off-hand I don't have a good idea of how one might solve such a complex problem as effectively parallel rewrites of the syntax tree.

holograph commented 7 years ago

I will take another look at it for 0.8, no promises on results though :-)