How to test a value on being AnyVal? - scala

Tried this:
scala> 2.isInstanceOf[AnyVal]
<console>:8: error: type AnyVal cannot be used in a type pattern or isInstanceOf test
2.isInstanceOf[AnyVal]
^
and this:
scala> 12312 match {
| case _: AnyVal => true
| case _ => false
| }
<console>:9: error: type AnyVal cannot be used in a type pattern or isInstanceOf test
case _: AnyVal => true
^
The message is very informative. I get that I can't use it, but what should I do?

I assume you want to test if something is a primitive value:
def testAnyVal[T](x: T)(implicit evidence: T <:< AnyVal = null) = evidence != null
println(testAnyVal(1)) // true
println(testAnyVal("Hallo")) // false
println(testAnyVal(true)) // true
println(testAnyVal(Boolean.box(true))) // false

I assume that your type is actually Any or you'd already know whether it was AnyVal or not. Unfortunately, when your type is Any, you have to test all the primitive types separately (I have chosen the variable names here to match the internal JVM designations for the primitive types):
(2: Any) match {
case u: Unit => println("Unit")
case z: Boolean => println("Z")
case b: Byte => println("B")
case c: Char => println("C")
case s: Short => println("S")
case i: Int => println("I")
case j: Long => println("J")
case f: Float => println("F")
case d: Double => println("D")
case l: AnyRef => println("L")
}
This works, prints I, and does not give an incomplete match error.

Related

Return type eliminated by erasure in Scala

Consider the following Scala code snippet:
def func(param: Any): Int = param match {
case f: (String => Int) => f("apple")
case i: Int => i
}
println(func((s: String) => s.length))
Works as expected, however, at compilation I get the following warning:
<console>:11: warning: non-variable type argument String in type pattern String => Int is unchecked since it is eliminated by erasure
case f: (String => Int) => f("apple")
How can I get rid of this warning message?
Thanks your help in advance!
The reason why you get the message is because of Java's generic type erasure. In this particular case, your function which is of type Function[String, Int] will be matched by any Function[A, B].
In order to get rid of this warning you should use scala typetags which will allow you to differentiate between the different function types.
The code snippet is below,
import scala.reflect.runtime.universe._
object Answer {
def function[A](param: A)(implicit tt: TypeTag[A]): String = param match {
case f: (String => Int) #unchecked if typeOf[String => Int] =:= typeOf[A] => f("apple").toString
case f: (Int => String) #unchecked if typeOf[Int => String] =:= typeOf[A] => f(32 + 1)
case s: String => s"hello $s"
}
def main (args: Array[String]) {
println(function((s: String) => s.length))
println(function((i: Int) => i.toString))
println(function("world"))
}
}
The key part is to have an implicit TypeTag[A] which is added at compile time which includes the metadata that the function typeOf needs to check the types of A against anything else.

Pattern Matching/Checking Arity of Function1

Given the following method:
scala> def f: List[Any] => Any = xs => 1234 // this output does not matter
f: List[Any] => Any
Is it possible to pattern match on List[Any] => Any? I don't see an unapply method on Function1, so I believe the answer is no.
Here's what I'm trying to do:
Example:
def foo(x: Any) = x match {
case ... // to handle the case of List[Any] => Any]?
case ...
}
Perhaps I can figure out the arity of x: Any to differentiate between List[Any] => Any versus everything else (_)?
EDIT:
I hope that I do not have to rely on f.toString == <function1>.
No, you can't match exactly on List[Any] => Any due to type erasure, but you can match on Function1 itself:
def foo(x: Any): String = x match {
case _: Function1[_, _] => "some function1"
case _ => "other"
}
Any other matching, like case _: (List[Any] => Any) => "function from list to any" will act the same as case _: Function1[_, _] => "some function":
scala> def foo(x: Any): String = x match {
| case _: (List[Any] => Any) => "function from list to any"
| case _ => "other"
| }
<console>:8: warning: non-variable type argument List[Any] in type pattern List[Any] => Any is unchecked since it is eliminated by erasure
case _: (List[Any] => Any) => "function from list to any"
^
foo: (x: Any)String
scala> def aaa(l: Any): Any = null //it's `Any => Any` - not `List[Any] => Any`!!
aaa: (l: Any)Any
scala> foo(aaa _)
res11: String = function from list to any
scala> foo(1)
res12: String = other
You can match purely on type, even without an unapply method:
def foo(x: Any): String = x match {
case _: (Any => Any) => "some function1"
case _ => "other"
}
And then you can check:
foo(f) //"some function1"
foo(1) //"other"

Understanding Erasure with Generic Case Class

For the following case class:
scala> case class Foo[T](name: String) {}
defined class Foo
scala> val foo = Foo[Int]("foo")
foo: Foo[Int] = Foo(foo)
Why will Scala let me, as I think it's doing, match on Foo[Int]? Isn't the Int erased?
scala> foo match {
| case _: Foo[Int] => "foo"
| case _ => "bar"
| }
res2: String = foo
But it shows a compile-time error when including another pattern match case?
scala> foo match {
| case _: Foo[String] => "string"
| case _: Foo[Int] => "int"
| case _ => "other"
| }
<console>:12: warning: non-variable type argument String in type pattern Foo[String] is unchecked since it is eliminated by erasure
case _: Foo[String] => "string"
^
<console>:12: error: pattern type is incompatible with expected type;
found : Foo[String]
required: Foo[Int]
case _: Foo[String] => "string"
^
class SuperFoo;
case class Foo[T](name: String) extends SuperFoo {}
val foo: SuperFoo = Foo[Int]("foo")
foo match {
case _: Foo[String] => "foo"
case _ => "bar"
} //> res0: String = foo + warning
In your case compiler knows exact type of foo.
It is erased. In your case compiler can statically check that foo is Foo[Int] and match expression here has sense only with Foo[Int], Foo[_] or Any (AnyRef, scala.Product, scala.Serializable).
But if you hide foo real class using, for example, base class Any:
val foo: Any = Foo[Int]("foo")
val res = foo match {
case _: Foo[String] => "string"
case _ => "other"
}
println(res) // string
You will get warning:
non-variable type argument String in type pattern Foo[String] is
unchecked since it is eliminated by erasure
and program will print "string".

Scala: Using a TypeTag to match on a Some's type

See the following code:
def createOption[T: TypeTag](referentialData: Any) : Option[T] = {
Option(referentialData) match {
case Some(camelMessage: CamelMessage) => {
Option(camelMessage.body) match {
case Some(option: T) => Some(option)
case _ => None
}
}
case _ => None
}
}
Basically I am looking to return an Option[T] if camelMessage.body is non-null and of type T.
The uses of Option(referentialData) is effectively referentialData != null
Likewise for Option(camelMessage.body)
How do I use the TypeTag to determine if camelMessage.body is of type T.
(I know this can be re-written to not use TypeTags and Options but I want to learn how to use TypeTags so please no suggestions to re-write, thanks!)
Edit
I tried a new approach as could not find a solution for the above, but could not get this one to work either:
def createOption[T](referentialData: Any) : Option[T] = {
Option(referentialData) match {
case Some(option) => Try(option.asInstanceOf[T]).toOption
case _ => None
}
}
When I invoke this using createOption[Long]("test") I was presuming to get a None back, but instead I got a Some(String)
Where am I going wrong here?
This is a duplicate of this one.
But you want to try it with ClassTag to show the limitation:
scala> def f[A: ClassTag](x: Any): Option[A] = x match {
| case y: A => println("OK"); Some(y) ; case _ => println("Nope"); None }
f: [A](x: Any)(implicit evidence$1: scala.reflect.ClassTag[A])Option[A]
scala> f[String]("foo")
OK
res0: Option[String] = Some(foo)
scala> f[Long](2L)
Nope
res1: Option[Long] = None
scala> f[java.lang.Long](new java.lang.Long(2L))
OK
res2: Option[Long] = Some(2)
scala> def f[A: TypeTag](x: Any): Option[A] = Option(x) match {
| case Some(y: A) => println("OK"); Some(y) ; case _ => println("Nope"); None }
<console>:51: warning: abstract type pattern A is unchecked since it is eliminated by erasure
case Some(y: A) => println("OK"); Some(y) ; case _ => println("Nope"); None }
^
f: [A](x: Any)(implicit evidence$1: reflect.runtime.universe.TypeTag[A])Option[A]

How to pattern-match against every numeric class in one case?

Suppose I have
def foo(x: Any) = x match {
case s: String => println(0)
case i: Int => println(1)
case l: Long => println(2)
//...
}
Is there any way to make something like the following?
def foo(x: Any) = x match {
case s: String => println(0)
case i: Numeric => println("Numeric")
}
You could match against the Number interface:
def foo(x: Any) = x match {
case s: String => println(0)
case i: java.lang.Number => println("Numeric")
}
You could try this:
def foo[A](x: A)(implicit num: Numeric[A] = null) = Option(num) match {
case Some(num) => println("Numeric: " + x.getClass.getName)
case None => println(0)
}
Then this
foo(1)
foo(2.0)
foo(BigDecimal(3))
foo('c')
foo("no")
will print
Numeric: java.lang.Integer
Numeric: java.lang.Double
Numeric: scala.math.BigDecimal
Numeric: java.lang.Character
0
Note that obtaining a null implicit parameter would not mean that no such implicit exist, but just that none was found at compile time in the search scope for implicits.