Add custom compile time checks to Scala

五迷三道 提交于 2019-12-10 10:44:06

问题


Suppose I have the following Scala code:

sealed trait Foo
sealed trait Bar
object Foo1 extends Foo
object Foo2 extends Foo
object Foo3 extends Foo
object Bar1 extends Bar
object Bar2 extends Bar
object Bar3 extends Bar
case class Hello(foo:Foo, bar:Bar)

val a = Hello(Foo1, Bar2) // allowed
val b = Hello(Foo2, Bar2) // suppose not allowed 

I need to catch at compile time if any incompatible combination is applied to Hello. Suppose only the following combinations are allowed: (Foo1, Bar1), (Foo1, Bar2), (Foo2, Bar3) and (Foo3, Bar3).

Is it possible to test this during compile time? I realize that plugins and macros may allow me to do this. Some hints would be appreciated. The above tutorials seem outdated for the latest versions of Scala (2.11.x), so pointers to other tutorials would also be great.

In the real example, there are about 10 instances of Foo and Bar, giving a total of 100 combinations, about half of them invalid. Furthermore, the valid combinations could change arbitrarily in future.

EDIT

Actual problem is bit more complex. The Hello method takes in Seq as follows:

case class Hello(foos:Seq[Foo], bars:Seq[Bar]) 

Examples of complex criteria are:

  1. If foos contain Foo1 then bars cannot have Bar1.
  2. foos cannot contain Foo1 and Foo3 together.

Code examples:

Hello(Seq(Foo1), Seq(Bar2, Bar3)) // valid 
Hello(Seq(Foo1, Foo3), Seq(Bar1)) // invalid due to rule 2

回答1:


There is a trick with types, not sure it is very beautiful (not beautiful at all), and you have to write lots of such rules manually, but mb you don't need to use heavy plugins / libs:

trait Validator[F, S] { }
object Validator {
    implicit object firstPair extends Validator[Foo1.type, Bar1.type]
    implicit object secondPair extends Validator[Foo1.type, Bar2.type]
    implicit object thirdPair extends Validator[Foo2.type, Bar3.type]
    implicit object fourthPair extends Validator[Foo3.type, Bar3.type]
}

case class Hello[F <: Foo, S <: Bar](foo: F, bar: S)(implicit v: Validator[F, S])

val a = Hello(Foo1, Bar2) // allowed
val b = Hello(Foo2, Bar2) // break in compile time


来源:https://stackoverflow.com/questions/29361147/add-custom-compile-time-checks-to-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!