2

I'm trying to use a partial function for some validations, lets take an example of a string:

def isLengthValid: PartialFunction[String, Option[String]] ={
  case s:String if s.length > 5 => Some("Invalid")
}

def isStringValid: PartialFunction[String, Option[String]] ={
  case s: String if s == "valid" => Some("Valid")
}

isLengthValid("valid") orElse isStringValid("valid")

expected output => Some("Valid")

But I'm getting a match Error:

scala.MatchError: valid (of class java.lang.String)

Could anyone help that what is going wrong here, because as per my understanding .isDefinedAt is called internally and is should not give matchError.

P.S ignore the inputs, this is just an example.

3 Answers 3

5

Your understanding is wrong. The ScalaDocs page clearly states, "It is the responsibility of the caller to call isDefinedAt before calling apply ...".

Your code isn't calling isDefinedAt, which is causing the exception, so you have to explicitly call it or you can employ other methods that hide the isDefinedAt internally.

Seq("valid") collect (isLengthValid orElse isStringValid)
//res0: Seq[Option[String]] = List(Some(Valid))

Seq("vlad") collect (isLengthValid orElse isStringValid)
//res1: Seq[Option[String]] = List()
Sign up to request clarification or add additional context in comments.

Comments

4

This works as intended if you write the last line as

(isLengthValid orElse isStringValid)("valid")

I suspect the problem is that your version desugars to (isLengthValid.apply("valid")).orElse(isStringValid.apply("valid"))

This means the apply is calculated before the orElse takes place, which means the partial function is treated as a total function and a match error is thrown as Valy Dia's answer explains. The orElse is actually being called on the result output, not the partial function.

2 Comments

Thanks this works, and this was what was i was looking for
@geek94; Really? This is what you were looking for? But this still throws a matchError when you try to validate a string like "vld". That's dangerous code.
2

The error message comes from the first expression - isLengthValid.

It is define only for string with a length stricly greater than 5. Hence when it is applied to a the string "valid" of length 5, it throws a MatchError:

scala>"valid".length
res5: Int = 5

isLengthValid("valid")
scala.MatchError: valid (of class java.lang.String)

If the method isLengthValid defined this way instead (Note the greater than equal sign), it wouldn't throw the MatchError :

def isLengthValid: PartialFunction[String, Option[String]] ={
  case s:String if s.length >= 5 => Some("Invalid")
}

scala>isLengthValid("valid")
res8: Option[String] = Some("Invalid")

And the original expression would return an Option:

scala>isLengthValid("valid") orElse isStringValid("valid")
res9: Option[String] = Some("Invalid")

What you could do here as well as explained in this question, is to use this definition instead:

val isLengthValid = new PartialFunction[String, Option[String]] {
  def isDefinedAt(x: String) = x.length > 5
  def apply(x: String) = Some("Invalid")
}

scala>isLengthValid("valid")
res13: Some[String] = Some("Invalid")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.