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 }
Boolean (equivalent to Java's boolean primitive type) is a subtype of scala. AnyVal. Instances of Boolean are not represented by an object in the underlying runtime system. There is an implicit conversion from scala.
Nullable boolean can be null, or having a value “true” or “false”. Before accessing the value, we should verify if the variable is null or not. This can be done with the classical check : if … else …
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With