1

As an example, we define a function that should convert 1, 3, 42 respectively to "foo", "bar", "qix" and all other integer to "X".

I've come up with 2 implementations : The method f need to be separate because it can be reuse in other context.

def f(i: Int): Option[String] = i match {
  case 1 => Some("foo")
  case 3 => Some("bar")
  case 42 => Some("qix")
  case _ => None
}

def g(i: Int) : String = f(i).getOrElse("X")

And :

def f_ : PartialFunction[Int, String] = {
  case 1 => "foo"
  case 3 => "bar"
  case 42 => "qix"
}

def g_(i: Int) : String = f_.orElse { case _ => "X" }(i)

I tend to prefer the second because it avoid many repetitive Some(…)

WDYT ?

Yann Moisan
  • 8,161
  • 8
  • 47
  • 91

5 Answers5

3

I'm not sure why you want to use option at all when you can just as easily do this and get the exact same result:

def f(i: Int): String = i match {
  case 1  => "foo"
  case 3  => "bar"
  case 42 => "qix"
  case _  => "X"
}

It even saves you a pesky getOrElse

You can even go one better and use neither a PartialFunction or a match and just do this:

def f: Int => String = {
  case 1  => "foo"
  case 3  => "bar"
  case 42 => "qix"
  case _  => "X"
}

Which saves you writing a disposable i

Electric Coffee
  • 11,733
  • 9
  • 70
  • 131
3

fScala's Map is already a partial function. So you can use it instead of defining your own function which does exactly what Map does - "A map from keys of type A to values of type B".
So all you have to do is:

val f = Map(1 -> "foo", 3 -> "bar", 42 -> "qix")
def g(i: Int) = f.getOrElse(i, "X")

f(1)  //foo
f(4)  // throw NoSuchElementException: Key not found: 4
f.get(1) // Some(foo)
f.get(4) // None
g(1)  //foo
g(4)  //X

Now you can use the function 'g' or reuse 'f' to other needs.

roterl
  • 1,883
  • 14
  • 24
1

Edited my example according to your comment:

def f(i: Int): Option[String] = {
  val map = Map(1 -> "foo", 3 -> "bar", 42 -> "qix")
  i match {
    case x if (map.contains(x)) => Some(map(x))
    case _ => None
  }
}

def g(i: Int) : String = f(i).getOrElse("X")

I think the function should react to integers outside the given range in some meaningful way. That's why I would prefer an Option.

Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
  • I've edit my question, it is not necessarly a range in my real-world cases. – Yann Moisan Sep 29 '14 at 08:38
  • 3
    @YannMoisan Next time please provide the full context. I answered your original question, then you modified it. Then I answered the modified question, now you modified it again. I will answer your questions, but I can't help, if you come up with different requirements every time I provide an answer. – Dennis Traub Sep 29 '14 at 08:49
  • 1
    @YannMoisan I modified my answer once more. But that should be enough. – Dennis Traub Sep 29 '14 at 08:53
0

Option is a good way to handle null value. Partial function is just a partial matching, they are not same, even though Option and PartialFunction both have similar orElse method

Due to partial function is a function, so it can be chained but option can not, Option is the way to handle null value.

For the partial function you can do like this, it is more like chain of responsibility

def f_1 : PartialFunction[Int, String] = {
  case 1 => "1"
}

def f_2 : PartialFunction[Int, String] = {
  case 2 => "2"
}

def f_3 : PartialFunction[Int, String] = {
  case 3 => "3"
}

f_1.orElse(f_2).orElse(f_3)(3)
Xiaohe Dong
  • 4,953
  • 6
  • 24
  • 53
0

You may want to try this. Here HashMap gives you fast lookup:

object SomeMain {
  import scala.collection.immutable.HashMap
  def f(i: Int): Option[String] = {
    HashMap(1 -> "foo", 3 -> "bar", 42 -> "qix").get(i).orElse(None)
  }

  def g(i: Int): String = f(i).getOrElse("X")

  def main(args: Array[String]) {
    List(1, 3, 42, 10) foreach { x => println(x + ": " + g(x)) }
  }
}

Output:

1: foo
3: bar
42: qix
10: X
tuxdna
  • 8,257
  • 4
  • 43
  • 61