Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: Can we combine guard conditions with pattern matches up front within the sealed case class declarations

Tags:

scala

Is it possible to combine guard conditions with pattern matching within sealed case class declarations?

I realise its possible to include guard conditions within the match block but I feel it would be beneficial to define this conditions up front in the sealed case classes. This would allow developers to define strict set of possible inputs which the compiler would check when pattern matching.

So in summary I'd like to be able to do the equivalent of something like this:

// create a set of pattern matchable cases with guards built in

sealed abstract class Args
case class ValidArgs1(arg1:Int,arg2:Int) if arg1>1 && arg2<10 extends Args
case class ValidArgs2(arg1:Int,arg2:Int) if arg1>5 && arg2<6 extends Args
case class InvalidArgs(arg1:Int,arg2:Int) if arg1<=1 && arg2>=10 extends Args


// the aim of this is to achieve pattern matching against an exhaustive set of 
// pre-defined possibilities

def process(args:Args){
    args match 
    {
        case ValidArgs1 = > // do this
        case ValidArgs2= > // do this
        case InvalidArgs = > // do this
    }
}
like image 316
newlogic Avatar asked Aug 11 '12 12:08

newlogic


1 Answers

+1 for an interesting speculative question. Since you are not operating at the type level, you cannot verify the instantiation at compile time, except maybe for very special checks with macros, e.g. when you are passing literals to the constructor.

On the other hand, your scenario, the pattern matching, is a runtime action. For that to work, you could use extractors instead of case classes.

case class Args(arg1: Int, arg2: Int)
object ValidArgs1 {
  def apply(arg1: Int, arg2: Int): Args = {
    val res = Args(arg1, arg2)
    require(unapply(res))
    res
  }
  def unapply(args: Args): Boolean = args.arg1 > 1 && args.arg2 < 10
}

def process(args: Args) = args match {
  case ValidArgs1() => "ok"
  case _            => "invalid"
}

process(ValidArgs1(2, 9))
process(Args(1, 10))
process(Args(3, 4))
like image 86
0__ Avatar answered Nov 02 '22 09:11

0__