Reputation: 5401
The code below checks for basic auth. Here resp
is the 401 unauthorized response. I check if an Authorization
header is present and if present I verify its value otherwise I call resp
:
def validate(authHeader: String): Boolean = {
//........
}
val authHeader = Option(request.getHeader("Authorization"))
authHeader match {
case Some(header) if header.startsWith("Basic ") => validate(header) match { case false => resp }
case _ => resp
}
When I compile it, it gives error for line match { case false => resp }
saying found: scala.Boolean(false) required: java.lang.Boolean
. I am confused about why its treating scala Boolean different from java Boolean.
I noticed there was a line import java.lang._
at the beginning of the file (I don't know why). I commented it out and the code give a warning instead of an error:
warning: match may not be exhaustive.
It would fail on the following input: true
I think this is because I didn't write the case true
. But what made the original error happen, and why does it only happen with import java.lang._
?
EDIT:
Here is a minimal example for the problem:
val f: java.lang.Boolean = false
val f2: scala.Boolean = false
/* The following line produces this error:
error: type mismatch;
found : scala.Boolean(false)
required: java.lang.Boolean
*/
f match { case false => 5 }
/* The following line produces this warning:
warning: match may not be exhaustive.
It would fail on the following input: true
*/
f2 match { case false => 5 }
Upvotes: 7
Views: 2849
Reputation: 38217
It seems that implicit conversions are not in effect in the case of pattern matching.
Consider:
scala> case class Foo(x: Int)
defined class Foo
scala> case class Bar(x: Int)
defined class Bar
scala> implicit def foo2bar(x: Foo) = Bar(x.x)
foo2bar: (x: Foo)Bar
scala> Foo(3) match { case Foo(3) => 3; case _ => 4 }
res19: Int = 3
scala> Foo(3) match { case Bar(3) => 3; case _ => 4 }
<console>:14: error: constructor cannot be instantiated to expected type;
found : Bar
required: Foo
Foo(3) match { case Bar(3) => 3; case _ => 4 }
^
Compare with:
scala> val f: java.lang.Boolean = false
f: Boolean = false
scala> f.<TAB>
asInstanceOf booleanValue compareTo isInstanceOf toString
scala> f || true
res21: Boolean = true
implicit conversions worked here, but not here:
scala> f match { case false => 3; case true => 4 }
<console>:15: error: type mismatch;
found : scala.Boolean(false)
required: java.lang.Boolean
f match { case false => 3; case true => 4 }
^
<console>:15: error: type mismatch;
found : scala.Boolean(true)
required: java.lang.Boolean
f match { case false => 3; case true => 4 }
^
I agree that this is quite counterintuitive but I doubt it could be fixed without introducing a special casing to the language, or making scalac
somehow recognize pattern matches where all patterns belong to a single type, and try to find an implicit conversion to that type. The workaround would be to do an explicit asInstanceOf[Boolean]
cast. Although it's odd that the following works fine:
scala> "foobar".startsWith("foo") match { case true => 3 ; case false => 4 }
res26: Int = 3
Upvotes: 4