1

Is there a more idiomatic/simpler way to write this code that deals with two Options?

object Test extends App {
  val colors = Some(1)
  val sizes = Some(2)

  val ids = colors match {
    case None => {
      sizes match {
        case None => getRegularIds
        case Some(sizes) => getSizeIds
      }
    }
    case Some(colors) => {
      sizes match {
        case None => getColorIds
        case Some(sizes) => getColorIds ++ getSizeIds
      }
    }
  }

  println(ids)

  def getColorIds = Seq(1,2,4)
  def getSizeIds = Seq(4,5,6)
  def getRegularIds = Seq(7,8,9)
}

Scala is so concise that it leads me to think there's probably a cleaner way to achieve the same results.

bad_coder
  • 11,289
  • 20
  • 44
  • 72
user455497
  • 637
  • 2
  • 6
  • 13

2 Answers2

2

Avoid nested matching:

val ids2 = (colors, sizes) match {
  case (None, None)       => getRegularIds
  case (Some(_), None)    => getColorIds
  case (None, Some(_))    => getSizeIds
  case (Some(_), Some(_)) => getColorIds ++ getSizeIds
}

You also could try something like:

colors.fold(defaultColors)(_ => getColors) ++ 
  sizes.fold(defaultSizes)(_ => getSizes)
Nikita
  • 4,435
  • 3
  • 24
  • 44
  • Thanks for the input. Much cleaner. – user455497 Jul 30 '16 at 20:24
  • On the other hand, nested logic is faster, since it results in a shallower branches. – Paul Draper Jul 31 '16 at 22:56
  • @PaulDraper Even if so, this 0.0000001% of performance gain doesn't outweigh maintainability. – Nikita Jul 31 '16 at 23:20
  • @ipoteka, in this case, sure. I was just pointing out that nested branches shouldn't always be avoided. Avoiding linear time branch resolution can be important in some cases, e.g. Scala's [@switch](http://www.scala-lang.org/api/2.11.8/#scala.annotation.switch). – Paul Draper Aug 01 '16 at 01:40
0

If your Seqs are Lists, you can also do this with Scalaz's Semigroup append, right out of the box:

import scalaz._, Scalaz._

scala> (colors.map(_ => getColorIds) |+| sizes.map(_ => getSizeIds))
         .getOrElse(getRegularIds)
res11: List[Int] = List(1, 2, 4, 4, 5, 6)

Here are the other outcomes (explicitly) to show what's going on:

scala> (Option(List(1, 2, 4)) |+| Option.empty[List[Int]]).getOrElse(getRegularIds)
res14: List[Int] = List(1, 2, 4)

scala> (Option.empty[List[Int]] |+| Option(List(4, 5, 6))).getOrElse(getRegularIds)
res15: List[Int] = List(4, 5, 6)

scala> (Option.empty[List[Int]] |+| Option.empty[List[Int]]).getOrElse(getRegularIds)
res16: List[Int] = List(7, 8, 9)

Unfortunately, there is no Semigroup[Seq]. See this answer for a better explanation as to why not.

Community
  • 1
  • 1
Michael Zajac
  • 55,144
  • 7
  • 113
  • 138