1

Is there a way to give a reference name to a variable when multiple cases are combined using match in Scala?

Code:

Assume Gender enum has three possible values like male, female and other.

(nameOption, genderOption) match {
    case (Some(name), Some(Gender.Male)) | (Some(name), Some(Gender.FeMale))=> s"$name gender is either male or female"
    case (None, Some(Gender.Male)) | (None, Some(Gender.FeMale)) => //some print statement
    case (Some(name), Some(Gender.Other)) =>  //some print statement
    case _ => //some print statement
}

First case case (Some(name), Some(Gender.Male)) | (Some(name), Some(Gender.FeMale)) is complier error as name is already defined in scope.

If I don't combine cases in my actual code cyclomatic complexity increases.

Puneeth Reddy V
  • 1,538
  • 13
  • 28
  • 3
    If you put `(Some(name), Some(Gender.Other))` first then you can just use `(Some(name),_)`. As a general rule, put the most specific cases first so that you can use catch-all matches later. – Tim Jun 25 '19 at 07:53
  • Scala would not allowed that syntax because the `name` replicated.But instead use the formula on how to get the tuple value. – Rex Jun 25 '19 at 07:59
  • 1
    Something like this. `case v: (a@Option[String], Some(Gender.Male)) | (b@Option[String], Some(Gender.FeMale))` or `case v@(a@Option[String], Some(Gender.Male)) | (b@Option[String], Some(Gender.FeMale))` .. – Rex Jun 25 '19 at 08:01
  • And (depending on your logic), you may be able to `.getOrElse` the optionality away before matching. – Thilo Jun 25 '19 at 08:15

3 Answers3

8

You can replace your first case to:

case (Some(name), Some(Gender.Male) |  Some(Gender.FeMale))=> s"$name gender is either male or female"

Update - even better - Thanks to @Astrid

case (Some(name), Some(Gender.Male | Gender.FeMale)) => s"$name gender is either male or female"
Gal Naor
  • 2,397
  • 14
  • 17
7

you can try the following

(nameOption, genderOption) match {
    case (Some(name), Some(gender) if (gender == Gender.Male || gender == Gender.Female) => s"$name gender is either male or female"

}
Dionysis Nt.
  • 955
  • 1
  • 6
  • 16
  • yeah it really depends on the case. My purpose was just to demonstrate how the same thing can be achieved by giving using the name variable. of course there is room for improvement – Dionysis Nt. Jun 25 '19 at 08:28
6

In addition to the answers already given, if you find yourself repeating the Gender.Male | Gender.FeMale match clause a lot in different parts of your code you might want to consider a custom extractor.

object BinaryGender {
  def unapply(gender: Gender.Gender) : Option[Gender.Gender] = {
    Some(gender).filter(_ != Gender.Other)
  }
}

(nameOption, genderOption) match {
  case (Some(name), Some(BinaryGender(_))) => s"$name gender is either male or female"
  case (None, Some(BinaryGender(_))) => //some print statement
  ...
}
Astrid
  • 1,808
  • 12
  • 24