3

Below are the two partial function that are expected to perform sme tasks but defined in diffrent ways.

val pf1 : PartialFunction[String, String] = { 
  case s : String if (s != null) =>  s.toUpperCase()
}
//> pf1  : PartialFunction[String,String] = <function1>

val lift1 = pf1.lift
//> lift1  : String => Option[String] = <function1>

val d1 = lift1(null)
//> d1  : Option[String] = None

val d2 = lift1("hello world")
//> d2  : Option[String] = Some(hello world)

val pf2 = PartialFunction[String, String] { 
  case s : String if(s != null) =>  s.toUpperCase()
}
//> pf2  : PartialFunction[String,String] = <function1>

val lift2 = pf2.lift
//> lift2  : String => Option[String] = <function1>

val d3 = lift2(null)
//> scala.MatchError: null

val d4 = lift2("hii")
//> d4  : Option[String] = Some(hii)

Why passing null to lift2 gives MatchError, when the definition of both lift1 and lift2 is same?

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
mogli
  • 1,549
  • 4
  • 29
  • 57
  • Jeez, guys, comment _the difference_. I spent 10 minutes staring at the white-space between `if` and `s(`, trying to figure out why that was important. (Clue for everyone else, it's the `=` after the type declaration that matters. – Michael Lorton Mar 20 '16 at 19:51

2 Answers2

1

If you look at PartialFunction.apply, you will see that it does a bit something different then what you've expected:

  /** Converts ordinary function to partial one
   *  @since   2.10
   */
  def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }

So it wraps a normal function into partial function that is defined on all domain. And that's why when you lift, you receive exception - because inside is still a normal not-lifted partial function, that is not defined

Archeg
  • 8,364
  • 7
  • 43
  • 90
1

Why passing null to lift2 gives MatchError, when the definition of both lift1 and lift2 is same?

They're not defined the same. When you define:

val pf1: PartialFunction[String, String] = {
  case s : String if (s != null) =>  s.toUpperCase()
}

The compiler creates a PartialFunction, like this:

this.pf1 = ({
    new <$anon: Function1>()
  }: PartialFunction);

But when you declare pf2 like this:

val pf2 = PartialFunction[String, String] {
  case s : String if(s != null) =>  s.toUpperCase()
}

You're actually telling the compiler "please take this Function1 and pass it to PartialFunction.apply. That is why the compiler does this:

this.pf2 = scala.PartialFunction.apply({
    (new <$anon: Function1>(): Function1)
});

Which actually wraps a Function1 inside a partial function. So when you call pf2.lift(null), it will internally call the Function1, causing a MatchError as you're seeing.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321