I want to check whether a obj in Scala is of type Array, not caring about whether what type of the values are inside. Is there some easy way to do this?
var x = Array(1,2,3)
x.isInstanceOf[Array[Any]] // which is false
I want it to be true.
Update:
I have a function:
def someFunction(obj: Any) {
if (obj.isInstanceOf[Int]) {
// do something
}
if (obj.isInstanceOf[String]) {
// do something
}
if (obj.isInstanceOf[Array[Any]) {
// for each of the obj inside the Array do something
}
}
array Array(1,2,3) is of type Int, so Array[Any] would weirdly return false only in case of Array collection.
If you don't care the type of Array, you can compare to Array[_] (array of whatever type)
scala> var x = Array(1,2,3)
x: Array[Int] = Array(1, 2, 3)
scala> x.isInstanceOf[Array[Int]]
res0: Boolean = true
scala> x.isInstanceOf[Array[_ <: Any]]
res7: Boolean = true
scala> x.isInstanceOf[Array[_ <: AnyVal]]
res12: Boolean = true
scala> x.isInstanceOf[Array[_]]
res13: Boolean = true
scala.Int extends AnyVal which extends Any you can explicitly mentions _ extends AnyVal.
But other scala collections like List[T] is instance of List[Any]
scala> List(1, 2).isInstanceOf[List[Any]]
res30: Boolean = true
scala> Seq(1, 2).isInstanceOf[Seq[Any]]
res33: Boolean = true
Also, List[T] is instance of Seq[Any], because List extends Seq, and T extends Any
scala> List(1, 2).isInstanceOf[Seq[Any]]
res35: Boolean = true
AND, for if else you can solve with pattern match way,
array match {
case x: Int => println("int")
case x: String => "string"
case Array[Int] => println("ints")
case Array[String] => println("strings")
case _ => println("whatever")
}
x.isInstanceOf[Array[_]]
use _ for container any type match. and for _ it's called existential type.
Document:
Underscore for existential type in Scala
Related
In scala, a pattern matching for a class has to be conducted in the following way:
val clz: Class[_] = ???
clz match {
case v if clz == classOf[String] =>
// do something
case v if clz == classOf[Int] =>
// do something
//...
}
The boilerplate code v if clz == is really redundant and I'd like to have them removed or reduced, since functions like classOf[String] and classOf[int] can be inlined and used like constant. So how can I do this?
There is some support, mostly in relation to array element types:
scala> import reflect.ClassTag
import reflect.ClassTag
scala> val c: Class[_] = classOf[Int]
c: Class[_] = int
scala> (ClassTag(c): Any) match { case ClassTag.Boolean => "bool" case ClassTag.Int => "int" }
res0: String = int
but the use case is to simplify type tests
scala> def f[A: ClassTag] = ("abc": Any) match { case _: A => "A" case _ => "other" }
f: [A](implicit evidence$1: scala.reflect.ClassTag[A])String
scala> f[Int]
res1: String = other
scala> f[String]
res2: String = A
Maybe one argument for classTag not looking like a stable id is that classOf[C] evaluated in different classloaders don't compare equal.
Imagine I have this class:
class Example {
val list = List(new Apple(), new Orange(), Banana());
def getIfPresent[T <: Fruit] : Option[T] = list.collectFirst { case x : T => x }
}
You use it like this:
val example = new Example();
match example.getIfPresent[Apple] {
case Some(apple) => apple.someAppleSpecificMethod();
case None => println("No apple");
}
Now, of course, this doesn't work in the JVM, because of type erasure. getIfPresent just matches on the type Fruit in the collectFirst partial function, instead of the actual type specified in the call.
I have tried to get my head around type tags and class tags, and really have no idea how I would implement the above method. The examples that I see are trying to do very different things. How could I achieve a method that does what I want, either with TypeTags or some other mechanism I'm unaware of?
Edit: m-z's answer below is the full solution, but here is how it looks with my example code:
class Example {
val list = List(new Apple(), new Orange(), Banana());
def getIfPresent[T <: Fruit : ClassTag] : Option[T] = list.collectFirst { case x : T => x }
}
Just needed to add : ClassTag!
You can do this using ClassTag, to an extent.
import scala.reflect.ClassTag
// Modify to apply whatever type bounds you find necessary
// Requires Scala ~2.11.5 or greater (not sure of the exact version, but 2.11.1 does not work, and 2.11.5 does)
def findFirst[A : ClassTag](list: List[Any]): Option[A] =
list collectFirst { case a: A => a }
val l = List(1, "a", false, List(1, 2, 3), List("a", "b"))
scala> findFirst[Boolean](l)
res22: Option[Boolean] = Some(false)
scala> findFirst[Long](l)
res23: Option[Long] = None
But there are some caveats with ClassTag, in that it will only match the class, and not the type:
scala> findFirst[List[String]](l)
res24: Option[List[String]] = Some(List(1, 2, 3)) // No!
You can use a TypeTag to get around this, but it won't work with a List[Any]. Here is one possible (sort of ugly) trick:
import scala.reflect.runtime.universe.{typeOf, TypeTag}
case class Tagged[A : TypeTag](a: A) {
def tpe = typeOf[A]
}
implicit class AnyTagged[A : TypeTag](a: A) {
def tag = Tagged(a)
}
def findFirst[A : TypeTag](list: List[Tagged[_]]): Option[A] =
list collectFirst { case tag # Tagged(a) if(tag.tpe =:= typeOf[A]) => a.asInstanceOf[A] }
The only way I can think of to hold onto the TypeTag of each element is to literally hold onto it with a wrapper class. So I have to construct the list like this:
val l = List(1.tag, "a".tag, false.tag, List(1, 2, 3).tag, List("a", "b").tag)
But it works:
scala> findFirst[List[String]](l)
res26: Option[List[String]] = Some(List(a, b))
There may be a more elegant way to construct such a list with TypeTags.
For fun, you can also try to do this with shapeless using an HList and select. The difference is that instead of returning Option[A], select will return A (the type you want), but if the HList contains no A, it won't compile.
import shapeless._
val l = 1 :: "a" :: false :: List(1, 2, 3) :: List("a", "b") :: HNil
scala> l.select[Boolean]
res0: Boolean = false
scala> l.select[Boolean]
res1: Boolean = false
scala> l.select[List[String]]
res2: List[String] = List(a, b)
scala> l.select[Long]
<console>:12: error: Implicit not found: shapeless.Ops.Selector[shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.::[List[Int],shapeless.::[List[String],shapeless.HNil]]]]], Long]. You requested an element of type Long, but there is none in the HList shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.::[List[Int],shapeless.::[List[String],shapeless.HNil]]]]].
l.select[Long]
^
I'm trying to test whether a method's return type exactly matches a supplied type.
Somehow, I've found two String Types that are not equal.
class VarAndValue {
#BeanProperty
val value = "";
}
class ScalaReflectionTest {
#Test
def myTest(): Unit = {
val type1 = universe.typeOf[String]
// Get return value of VarAndValue.getValue
val type2 = universe.typeOf[VarAndValue].
declarations.
filter { m => m.name.decoded == "getValue" && m.isMethod }.
head.
asInstanceOf[universe.MethodSymbol].
returnType
println(type1) // String
println(type2) // String
println(type1.getClass())
println(type2.getClass()) // !=type1.getClass() !!
println(type1==type2) // False
}
}
yields...
String
String
class scala.reflect.internal.Types$TypeRef$$anon$3
class scala.reflect.internal.Types$TypeRef$$anon$6
false
How can I filter methods of a class by their return type? (It seems very difficult if I can test for equality of the return types).
Scala 2.10
UPDATE:
I can't drop into the Java reflection universe because this erased type information for generics like List[Int] (which become List[Object] is java-land where they're really List[java.lang.Integer]). I need my matched to pay attention to the generic parameter information that the scala type universe preserves.
Use =:= to compare types.
scala> import beans._
import beans._
scala> :pa
// Entering paste mode (ctrl-D to finish)
class VarAndValue {
#BeanProperty
val value = "";
}
// Exiting paste mode, now interpreting.
defined class VarAndValue
scala> import reflect.runtime._, universe._
import reflect.runtime._
import universe._
scala> val str = typeOf[String]
str: reflect.runtime.universe.Type = String
scala> val ms = typeOf[VarAndValue].declarations filter (m => m.isMethod && m.name.decoded == "getValue")
warning: there were two deprecation warnings; re-run with -deprecation for details
ms: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method getValue)
scala> val mm = ms.toList
mm: List[reflect.runtime.universe.Symbol] = List(method getValue)
scala> val m = mm.head.asInstanceOf[MethodSymbol]
m: reflect.runtime.universe.MethodSymbol = method getValue
scala> val t = m.returnType
t: reflect.runtime.universe.Type = java.lang.String
scala> println(t)
java.lang.String
scala> println(str)
String
scala> str == t
res2: Boolean = false
scala> str match { case `t` => }
scala.MatchError: String (of class scala.reflect.internal.Types$AliasNoArgsTypeRef)
... 33 elided
scala> str =:= t
res4: Boolean = true
scala> str match { case TypeRef(a,b,c) => (a,b,c) }
res5: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (scala.Predef.type,type String,List())
scala> t match { case TypeRef(a,b,c) => (a,b,c) }
res6: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (java.lang.type,class String,List())
Depending on what you're going for, consider that conforming types can have differing representations:
scala> typeOf[List[Int]]
res11: reflect.runtime.universe.Type = scala.List[Int]
scala> type X = List[Int]
defined type alias X
scala> typeOf[X].dealias
res12: reflect.runtime.universe.Type = List[scala.Int]
scala> res11 =:= res12
res13: Boolean = true
scala> res11 == res12
res14: Boolean = false
scala> typeOf[X] <:< res11
res15: Boolean = true
scala> typeOf[X] =:= res11
res16: Boolean = true
Turns out this is the way to compare types ...
type1 match {
case type2 => true
case _ => false
}
which gives a different answer than type1==type.
Scala is a strange beast.
I have an heterogeneous List like the following one:
val l = List(1, "One", true)
and I need to filter its objects by extracting only the ones belonging to a given Class. For this purpose I wrote a very simple method like this:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (_.asInstanceOf[AnyRef].getClass() == c)
Note that I am obliged to add the explicit conversion to AnyRef in order to avoid this compilation problem:
error: type mismatch;
found : _$1 where type _$1
required: ?{val getClass(): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method any2stringadd in object Predef of type (x: Any)scala.runtime.StringAdd
and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
are possible conversion functions from _$1 to ?{val getClass(): ?}
l filter (_.getClass() == c)
However in this way the invocation of:
filterByClass(l, classOf[String])
returns as expected:
List(One)
but of course the same doesn't work, for example, with Int since they extends Any but not AnyRef, so by invoking:
filterByClass(l, classOf[Int])
the result is just the empty List.
Is there a way to make my filterByClass method working even with Int, Boolean and all the other classes extending Any?
The collect method already does what you want. For example to collect all Ints in a collection you could write
xs collect { case x: Int => x }
This of course only works when you hardcode the type but as primitives are handled differently from reference types it is actually better to do so. You can make your life easier with some type classes:
case class Collect[A](collect: PartialFunction[Any,A])
object Collect {
implicit val collectInt: Collect[Int] = Collect[Int]({case x: Int => x})
// repeat for other primitives
// for types that extend AnyRef
implicit def collectAnyRef[A <: AnyRef](implicit mf: ClassManifest[A]) =
Collect[A]({ case x if mf.erasure.isInstance(x) => x.asInstanceOf[A] })
}
def collectInstance[A : Collect](xs: List[_ >: A]) =
xs.collect(implicitly[Collect[A]].collect)
Then you can use it without even passing a Class[A] instance:
scala> collectInstance[Int](l)
res5: List[Int] = List(1)
scala> collectInstance[String](l)
res6: List[String] = List(One)
Using isInstanceOf:
scala> val l = List(1, "One", 2)
l: List[Any] = List(1, One, 2)
scala> l . filter(_.isInstanceOf[String])
res1: List[Any] = List(One)
scala> l . filter(_.isInstanceOf[Int])
res2: List[Any] = List(1, 2)
edit:
As the OP requested, here's another version that moves the check in a method. I Couldn't find a way to use isInstanceOf and so I changed the implementation to use a ClassManifest:
def filterByClass[A](l: List[_])(implicit mf: ClassManifest[A]) =
l.filter(mf.erasure.isInstance(_))
Some usage scenarios:
scala> filterByClass[String](l)
res5: List[Any] = List(One)
scala> filterByClass[java.lang.Integer](l)
res6: List[Any] = List(1, 2)
scala> filterByClass[Int](l)
res7: List[Any] = List()
As can be seen above, this solution doesn't work with Scala's Int type.
The class of an element in a List[Any] is never classOf[Int], so this is behaving as expected. Your assumptions apparently leave this unexpected, but it's hard to give you a better way because the right way is "don't do that."
What do you think can be said about the classes of the members of a heterogenous list? Maybe this is illustrative. I'm curious how you think java does it better.
scala> def f[T: Manifest](xs: List[T]) = println(manifest[T] + ", " + manifest[T].erasure)
f: [T](xs: List[T])(implicit evidence$1: Manifest[T])Unit
scala> f(List(1))
Int, int
scala> f(List(1, true))
AnyVal, class java.lang.Object
scala> f(List(1, "One", true))
Any, class java.lang.Object
This worked for me. Is this what you want?
scala> val l = List(1, "One", true)
l: List[Any] = List(1, One, true)
scala> l filter { case x: String => true; case _ => false }
res0: List[Any] = List(One)
scala> l filter { case x: Int => true; case _ => false }
res1: List[Any] = List(1)
scala> l filter { case x: Boolean => true; case _ => false }
res2: List[Any] = List(true)
Despite my solution could be less elegant than this one I find mine quicker and easier. I just defined a method like this:
private def normalizeClass(c: Class[_]): Class[_] =
if (classOf[AnyRef].isAssignableFrom((c))) c
else if (c == classOf[Int]) classOf[java.lang.Integer]
// Add all other primitive types
else classOf[java.lang.Boolean]
So by using it in my former filterByClass method as it follows:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (normalizeClass(c).isInstance(_))
the invocation of:
filterByClass(List(1, "One", false), classOf[Int])
just returns
List(1)
as expected.
At the end, this problem reduces to find a map between a primitive and the corresponding boxed type.
Maybe a help can arrive from scala.reflect.Invocation (not included in the final version of 2.8.0), the getAnyValClass function in particular (here slightly edited)
def getAnyValClass(x: Any): java.lang.Class[_] = x match {
case _: Byte => classOf[Byte]
case _: Short => classOf[Short]
case _: Int => classOf[Int]
case _: Long => classOf[Long]
case _: Float => classOf[Float]
case _: Double => classOf[Double]
case _: Char => classOf[Char]
case _: Boolean => classOf[Boolean]
case _: Unit => classOf[Unit]
case x#_ => x.asInstanceOf[AnyRef].getClass
}
With this function the filter is as easy as
def filterByClass[T: Manifest](l:List[Any]) = {
l filter (getAnyValClass(_) == manifest[T].erasure)
}
and the invocation is:
filterByClass[Int](List(1,"one",true))
I've wrapped a Message and would like to log which message I've wrapped.
val any :Any = msg.wrappedMsg
var result :Class[_] = null
The only solution I could find is matching everything:
result = any match {
case x:AnyRef => x.getClass
case _:Double => classOf[Double]
case _:Float => classOf[Float]
case _:Long => classOf[Long]
case _:Int => classOf[Int]
case _:Short => classOf[Short]
case _:Byte => classOf[Byte]
case _:Unit => classOf[Unit]
case _:Boolean=> classOf[Boolean]
case _:Char => classOf[Char]
}
I wonder if there's a better solution?
The following 2 approaches do not work :(
result = any.getClass //error
// type mismatch; found : Any required: ?{val getClass: ?}
// Note: Any is not implicitly converted to AnyRef.
// You can safely pattern match x: AnyRef or cast x.asInstanceOf[AnyRef] to do so.
result = any match {
case x:AnyRef => x.getClass
case x:AnyVal => /*voodoo to get class*/ null // error
}
//type AnyVal cannot be used in a type pattern or isInstanceOf
You can safely call .asInstanceOf[AnyRef] on any Scala value, which will box primitives:
scala> val as = Seq("a", 1, 1.5, (), false)
as: Seq[Any] = List(, 1, 1.5, (), false)
scala> as map (_.asInstanceOf[AnyRef])
res4: Seq[AnyRef] = List(a, 1, 1.5, (), false)
From there, you can call getClass.
scala> as map (_.asInstanceOf[AnyRef].getClass)
res5: Seq[java.lang.Class[_]] = List(class java.lang.String, class java.lang.Int
eger, class java.lang.Double, class scala.runtime.BoxedUnit, class java.lang.Boo
lean)
Tested with 2.8.0.RC6, I don't know it this worked in 2.7.7.
Definitely new in 2.8 are the companion objects for the classes derived from AnyVal. They contain handy box and unbox methods:
scala> Int.box(1)
res6: java.lang.Integer = 1
scala> Int.unbox(res6)
res7: Int = 1
Won't casting just do the trick, as suggested in the error message?
scala> val d:Double = 0.0
d: Double = 0.0
scala> d.asInstanceOf[AnyRef].getClass
res0: java.lang.Class[_] = class java.lang.Double
As of scala 2.10.0, getClass is available on Any (and not just on AnyRef), so you don't need to do any contorsion anymore and can just do any.getClass.
Note though that you still must be prepared to handlet the dual relation between primitive types and their boxed version.
By example getClass on an integer value will return either java.lang.Integer.TYPE (the class of the primitive Int type) or classOf[java.lang.Integer] depending on the static type of the value:
scala> 123.getClass
res1: Class[Int] = int
scala> val x : Int = 123
x: Int = 123
scala> x.getClass
res2: Class[Int] = int
scala> val x: AnyVal = 123
x: AnyVal = 123
scala> x.getClass
res3: Class[_] = class java.lang.Integer
scala> val x: Any = 123
x: Any = 123
scala> x.getClass
res4: Class[_] = class java.lang.Integer