In the following code, I am getting a compilation error stating that I have a type mismatch on 'x':
val someRef: java.lang.Long = 42L
someRef match {
case x: Long => println("The answer: " + x)
case _ => println("Unknown")
}
How do I get Scala to auto-unbox someRef in the match statement?
The type system doesn't know about boxing at this level. But it does know that if there is an Any, a boxed Long is really (presumably) supposed to be just a Long (from the AnyVal part of the class inheritance tree). So:
val someRef: java.lang.Long = 42L
(someRef: Any) match {
case x : Long => println("The answer is " + x)
case _ => println("What answer?")
}
Related
I wrote some events in FSM, and discovered something I can not explain when pattern matching. I thought the following was completely legal, that is that I can send this actor either a message which is a vector[A] or vector[B].
when(State) {
case Event(content: Vector[A], _) => {
println("matched A")
stay
}
case Event(content: Vector[B], _) => {
println("matched B")
stay
}
}
However,
if I send the actor a vector[B] message it leads to
java.lang.ClassCastException: B cannot be cast to A
So basically it tries to match the first event eventhough the next would match.
I tried to make an even simpler pattern match example;
object Pattern extends App {
val n = Vector(1,2,3)
val s = Vector("S", "S", "S")
n match{
case e:Vector[String] => println("matched string")
case v:Vector[Int] => println("matched int")
}
}
This is actually not legal;
Error:(8, 12) pattern type is incompatible with expected type;
found : Vector[String]
required: scala.collection.immutable.Vector[Int]
case e:Vector[String] => println("matched string")
However, I am allowed to run my code if I do the following cast;
object Pattern extends App {
val n = Vector(1,2,3).asInstanceOf[Vector[Any]]
val s = Vector("S", "S", "S")
n match{
case e:Vector[String] => println(n(0).getClass)
case v:Vector[Int] => println("matched int")
}
}
The thing I find strange then is that I apparently say that Any could match a String, but the print is java.lang.Integer. So should I think of it as I have an vector[Int] that I say is a Vector[Any], since Vector[Any] could be a Vector[String] it matches that pattern, and again since it really is a vector[Int] I mask as Vector[Any] the print is fine too.
Could someone explain these pattern matching observations?
and how should I set up the messages so my state can handle both messages of Vector[A] and Vector[B]?
Due to type erasure of jvm type information is lost at runtime this kind of pattern matching (pattern matching with higher kinded types) is not supported directly.
Here are the ways to get around this problem
Instead I recommend you to wrap the vector in another container.
sealed trait Vectors
case class VectorString(vs: Vector[String]) extends Vectors
case class VectorInt(vi: Vector[Int]) extends Vectors
def doStuff(v: Vectors) = v match {
case VectorString(vs) => //be sure that vs is Vector[String]
case VectorInt(vi) =>
}
Ways to pattern match generic types in Scala
Using TypeTag
import scala.reflect.runtime.universe._
def handle[A: TypeTag](a: A): Unit =
typeOf[A] match {
case t if t =:= typeOf[List[String]] =>
// list is a string list
val r = a.asInstanceOf[List[String]].map(_.length).sum
println("strings: " + r)
case t if t =:= typeOf[List[Int]] =>
// list is an int list
val r = a.asInstanceOf[List[Int]].sum
println("ints: " + r)
case _ => // ignore rest
}
val ints: List[Int] = Nil
handle(List("hello", "world")) // output: "strings: 10"
handle(List(1, 2, 3)) // output: "ints: 6"
handle(ints) // output: "ints: 0" it works!
I am writing a Hive UDF in Scala (because I want to learn scala). To do this, I have to override three functions: evaluate, initialize and getDisplayString.
In the initialize function I have to:
Receive an array of ObjectInspector and return an ObjectInspector
Check if the array is null
Check if the array has the correct size
Check if the array contains the object of the correct type
To do this, I am using pattern matching and came up with the following function:
override def initialize(genericInspectors: Array[ObjectInspector]): ObjectInspector = genericInspectors match {
case null => throw new UDFArgumentException(functionNameString + ": ObjectInspector is null!")
case _ if genericInspectors.length != 1 => throw new UDFArgumentException(functionNameString + ": requires exactly one argument.")
case _ => {
listInspector = genericInspectors(0) match {
case concreteInspector: ListObjectInspector => concreteInspector
case _ => throw new UDFArgumentException(functionNameString + ": requires an input array.")
}
PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(listInspector.getListElementObjectInspector.asInstanceOf[PrimitiveObjectInspector].getPrimitiveCategory)
}
}
Nevertheless, I have the impression that the function could be made more legible and, in general, prettier since I don't like to have code with too many levels of indentation.
Is there an idiomatic Scala way to improve the code above?
It's typical for patterns to include other patterns. The type of x here is String.
scala> val xs: Array[Any] = Array("x")
xs: Array[Any] = Array(x)
scala> xs match {
| case null => ???
| case Array(x: String) => x
| case _ => ???
| }
res0: String = x
The idiom for "any number of args" is "sequence pattern", which matches arbitrary args:
scala> val xs: Array[Any] = Array("x")
xs: Array[Any] = Array(x)
scala> xs match { case Array(x: String) => x case Array(_*) => ??? }
res2: String = x
scala> val xs: Array[Any] = Array(42)
xs: Array[Any] = Array(42)
scala> xs match { case Array(x: String) => x case Array(_*) => ??? }
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:230)
... 32 elided
scala> Array("x","y") match { case Array(x: String) => x case Array(_*) => ??? }
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:230)
... 32 elided
This answer should not be construed as advocating matching your way back to type safety.
I am trying to use pattern matching to detect a generic type of my own custom type based on this answer.
The code provided by author works as expected:
import scala.reflect.runtime.{universe => ru}
def matchList[A: ru.TypeTag](list: List[A]) = list match {
case strlist: List[String #unchecked] if ru.typeOf[A] =:= ru.typeOf[String] => println("A list of strings!")
case intlist: List[Int #unchecked] if ru.typeOf[A] =:= ru.typeOf[Int] => println("A list of ints!")
}
matchList(List("a", "b", "c"))
matchList(List(1,2,3))
correctly displays:
A list of strings!
A list of ints!
Now based on this I am trying to apply same pattern to detect the generic type of my custom class Foo. The code below is copy-pased, except it uses Foo instead of List:
import scala.reflect.runtime.{universe => ru}
class Foo[T](val data: T)
def matchFoo[A: ru.TypeTag](foo: Foo[A]) = {
println("Is string = " + (ru.typeOf[A] =:= ru.typeOf[String]))
println("Is int = " + (ru.typeOf[A] =:= ru.typeOf[Int]))
foo match {
case fooStr: Foo[String #unchecked] if ru.typeOf[A] =:= ru.typeOf[String] => println("Found String")
case fooInt: Foo[Int #unchecked] if ru.typeOf[A] =:= ru.typeOf[Int] => println("Found Int")
}
}
matchFoo(new Foo[String]("str"))
println("------------")
matchFoo(new Foo[Int](123))
Only this time it outputs not what I was expecting:
Is string = true
Is int = false
Found String
------------
Is string = false
Is int = true
Found String // wth?
How can the second call matchFoo(new Foo[Int](123)) display Found String? As you can see I even explicitly printed out the match conditions, and they are fine.
The code online: http://goo.gl/b5Ta7h
EDIT:
I got it working by extracting match conditions into a variable:
def matchFoo[A: ru.TypeTag](foo: Foo[A]) = {
val isString: Boolean = ru.typeOf[A] =:= ru.typeOf[String]
val isInt: Boolean = ru.typeOf[A] =:= ru.typeOf[Int]
println("Is string = " + isString)
println("Is int = " + isInt)
foo match {
case fooStr: Foo[String #unchecked] if isString => println("Found String")
case fooInt: Foo[Int #unchecked] if isInt => println("Found Int")
}
}
Code online: http://goo.gl/mLxYY2
But in my opinion the original version should also work. I don't think I'm missing operator precedence here, since wrapping conditions into parenthesis also doesn't help.
Is it a bug in Scala? I'm using Scala SDK v. 2.11.5 and JDK v. 1.8.0_25. The online CodingGround uses Scala SDK v. 2.10.3.
EDIT 2:
I've opened an issue in Scala's bugtracker for this. You can vote for it here.
This looks very much like a bug in the compiler which does not resolve the correct implicit (could be the presence of the #unchecked?).
case fooStr: Foo[String #unchecked] if ru.typeOf[A] =:= ru.typeOf[String] =>
println(implicitly[TypeTag[String]]) // will print TypeTag[Int]
By looking at the byte code, the compiler uses the TypeTag passed to the method ($evidence).
A (limited) workaround could be to use ru.definitions.IntTpe:
case fooStr: Foo[Int #unchecked] if ru.typeOf[A] =:= ru.definitions.IntTpe =>
println("That's an Int")
I believed for a long time that this two constructions is equivalent:
if (myVar.isInstanceOf[MyType]) myVar.asInstanceOf[MyType].doSomething
and
myVar match {
case my : MyType => my.doSomething
case _ => {}
}
But suddenly I've found that I get type error while trying to match Number value to the Double type, but asInstanceOf[Double] works fine. WTF is happening?
simple example for scala REPL
val d = 3.5
val n : Number = d
n.isInstanceOf[Double]
works fine:
Boolean = true
but
n match {
case x : Double => println("double")
case _ => println("not a double")
}
produces type error:
:11: error: pattern type is incompatible with expected type;
found : Double
required: Number
case x : Double => println("double")
scala.Double is not inherited from java.lang.Number but from AnyVal.
You want to match on java.lang.Double:
n match {
case x : java.lang.Double => println("double")
case _ => println("not a double")
}
When using
val d = 3.5
val n : Number = d // implicit conversion from scala.Double to java.lang.Double
scala.Double is implicitly converted to java.lang.Double during assignment to n
what is wrong in this piece of code?
(Left("aoeu")) match{case Right(x) => ; case Left(x) => }
<console>:6: error: constructor cannot be instantiated to expected type;
found : Right[A,B]
required: Left[java.lang.String,Nothing]
why the pattern matcher just doesn't skip the Right and examine Left?
Implicit typing is inferring that Left("aoeu") is a Left[String,Nothing]. You need to explicitly type it.
(Left("aoeu"): Either[String,String]) match{case Right(x) => ; case Left(x) => }
It seems that pattern matching candidates must always be of a type matching the value being matched.
scala> case class X(a: String)
defined class X
scala> case class Y(a: String)
defined class Y
scala> X("hi") match {
| case Y("hi") => ;
| case X("hi") => ;
| }
<console>:11: error: constructor cannot be instantiated to expected type;
found : Y
required: X
case Y("hi") => ;
^
Why does it behave like this? I suspect there is no good reason to attempt to match on an incompatible type. Attempting to do so is a sign that the developer is not writing what they really intend to. The compiler error helps to prevent bugs.
scala> val left: Either[String, String] = Left("foo")
left: Either[String,String] = Left(foo)
scala> left match {
| case Right(x) => "right " + x
| case Left(x) => "left " + x }
res3: java.lang.String = left foo