{ sealed trait Sealed; case object Foo extends Sealed; case class Bar(s: String) extends Sealed; trait Baz extends Sealed }
import scala.reflect.runtime.universe._
val List(bar, baz, foo) = symbolOf[Sealed].asClass.knownDirectSubclasses.toList
I've tried .asClass.primaryConstructor.isStatic, but that doesn't work if the sealed trait is defined as dependent type.
Symbol#isModuleClass looks like it can determine if the symbol is an object, and foo.asClass.isClass can determine whether it has the case modifier. Note that asClass will throw an exception if you use it on other type of symbol, though (method, term, etc).
Object test:
scala> bar.isModuleClass // case class
res28: Boolean = false
scala> baz.isModuleClass // trait
res29: Boolean = false
scala> foo.isModuleClass // case object
res30: Boolean = true
For other types:
scala> val a = ""
a: String = ""
scala> symbolOf[a.type].isModuleClass
res34: Boolean = false
case class A(value: String) ; object A { def default = A("") }
scala> symbolOf[A].isModuleClass
res35: Boolean = false
scala> symbolOf[A.type].isModuleClass
res36: Boolean = true
Based on the API documentation and SI-6012 it seems like isModule should also work, but it only returns true for the companionSymbol.
Case test:
scala> bar.asClass.isCaseClass // case class
res44: Boolean = true
scala> baz.asClass.isCaseClass // trait
res45: Boolean = false
scala> foo.asClass.isCaseClass // case object
res46: Boolean = true
For other types (same definitions as the examples above):
scala> symbolOf[a.type].asClass.isCaseClass // plain singleton object
res47: Boolean = false
scala> symbolOf[A].asClass.isCaseClass // case class
res48: Boolean = true
scala> symbolOf[A.type].asClass.isCaseClass // non-case object
res49: Boolean = false
Putting it together:
def isCaseObject(symbol: Symbol): Boolean =
symbol.isModuleClass && symbol.asClass.isCaseClass
scala> isCaseObject(bar)
res50: Boolean = false
scala> isCaseObject(baz)
res51: Boolean = false
scala> isCaseObject(foo)
res52: Boolean = true
scala> isCaseObject(symbolOf[a.type])
res53: Boolean = false
scala> isCaseObject(symbolOf[A])
res54: Boolean = false
scala> isCaseObject(symbolOf[A.type])
res55: Boolean = false
Related
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
Given:
scala> case class ParentPath(private val x: String) {
| val value = x.dropWhile(_ == '/')
| }
I can make a ParentPath:
scala> ParentPath("/foo")
res10: ParentPath = ParentPath(/foo)
I can't access its x (due to private, it appears).
scala> res10.
asInstanceOf canEqual copy isInstanceOf productArity productElement productIterator productPrefix toString value
I can get its value.
scala> res10.value
res11: String = foo
However, I'd prefer to return its value rather than x upon a pattern match:
scala> res10 match { case ParentPath(x) => x}
res13: String = /foo
How can I pattern match with value rather than x?
scala> ParentPath.unapply(res10)
res15: Option[String] = Some(/foo)
I tried to override ParentPath#unapply, but got a compile-time error:
scala> case class ParentPath(private val x: String) {
| val value = "foo"
| override def unapply(p: ParentPath): Option[String] = Some(value)
| }
<console>:15: error: method unapply overrides nothing
override def unapply(p: ParentPath): Option[String] = Some(value)
^
The unapply method belongs in the companion object, and you cannot override it for a case class, anyway. For a normal class, this will work. Or, if you simply use a differently named object that has an unapply method of the same signature.
class ParentPath(private val x: String) {
val value = "foo"
}
object ParentPath {
def unapply(p: ParentPath): Option[String] = Some(p.value)
}
scala> new ParentPath("/foo") match { case ParentPath(x) => x }
res1: String = foo
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.
If I have a method...
def arrayConformsTo[A](as: Array[_]) = ???
... where I can add Context Bounds to A as needed. I want this method to look at the component type of the Array and return true if this is a subtype of A. So, for example:
arrayConformsTo[Int](Array(1, 2, 3)) //returns true
arrayConformsTo[String](Array(1, 2, 3)) //returns false
Prior to 2.10, this would have been done as follows:
def arrayConformsTo[A: Manifest](as: Array[_]) =
ClassManifest.fromClass(as.getClass.getComponentType) <:< manifest[A]
However this now compiles with deprecation warnings
<console>:8: warning: method <:< in trait ClassManifestDeprecatedApis is deprecated: Use scala.reflect.runtime.universe.TypeTag for subtype checking instead
ClassManifest.fromClass(as.getClass.getComponentType) <:< manifest[A]
^
<console>:8: warning: value ClassManifest in object Predef is deprecated: Use scala.reflect.ClassTag instead
ClassManifest.fromClass(as.getClass.getComponentType) <:< manifest[A]
My first guess at this is as follows:
scala> def arrayConformsTo[A: reflect.ClassTag](as: Array[_]) =
| reflect.ClassTag(as.getClass.getComponentType) <:< implicitly[reflect.ClassTag[A]]
But this gives a deprecation warning as well
<console>:8: warning: method <:< in trait ClassManifestDeprecatedApis is deprecated: Use scala.reflect.runtime.universe.TypeTag for subtype checking instead
reflect.ClassTag(as.getClass.getComponentType) <:< implicitly[reflect.ClassTag[A]]
^
It tells me to use TypeTag. But how? Is this even a valid thing to ask of reflection?
Appendix: this seems to work reasonably well for what I need, although it does not work for AnyVal:
scala> def arrayConformsTo[A: reflect.ClassTag](as: Array[_]) =
| implicitly[reflect.ClassTag[A]].runtimeClass isAssignableFrom as.getClass.getComponentType
The scala reflection api sure is quite a labyrinth, but at least it is comprehensive:
import scala.reflect.runtime.{universe => ru}
def arrayConformsTo[A: ru.TypeTag](as: Array[_]) = {
val mirror = ru.runtimeMirror( getClass.getClassLoader )
val classSym = mirror.classSymbol( as.getClass.getComponentType )
classSym.toType <:< implicitly[ru.TypeTag[A]].tpe
}
REPL test:
scala> arrayConformsTo[Float]( Array[Float]() )
res9: Boolean = true
scala> arrayConformsTo[Int]( Array[Float]() )
res10: Boolean = false
scala> arrayConformsTo[AnyVal]( Array[Float]() )
res11: Boolean = true
scala> arrayConformsTo[AnyVal]( Array[Float]() )
res12: Boolean = true
scala> arrayConformsTo[Any]( Array[Float]() )
res13: Boolean = true
scala> arrayConformsTo[Any]( Array[Float]() )
res14: Boolean = true
scala> arrayConformsTo[AnyRef]( Array[Float]() )
res15: Boolean = false
scala> arrayConformsTo[AnyRef]( Array[Float]() )
res16: Boolean = false
(This edit by the OP for reasons of completeness)
Another solution (not requiring scala-reflect.jar), albeit one which does not preserve the Float <:< AnyVal is true property is to use a ClassTag as an extractor:
scala> def arrayConformsTo[A](as: Array[_])(implicit arrayOfA: ClassTag[Array[A]])
| = as match {
| case arrayOfA(_) => true
| case _ => false
| }
This works for me w/o any compiler warnings:
def arrayConformsTo[A](as: Array[_])(implicit t:ClassTag[A]) = {
ClassTag(as.getClass().getComponentType()) equals t
}
Then this prints true and then false
println(arrayConformsTo[Int](Array(1,2,3)))
println(arrayConformsTo[String](Array(1,2,3)))
Is it possible to ignore a field of a case class in the equals/haschode method of the case class?
My use case is that I have a field that is essentially metadata for rest of the data in the class.
Only parameters in the first parameter section are considered for equality and hashing.
scala> case class Foo(a: Int)(b: Int)
defined class Foo
scala> Foo(0)(0) == Foo(0)(1)
res0: Boolean = true
scala> Seq(0, 1).map(Foo(0)(_).hashCode)
res1: Seq[Int] = List(-1669410282, -1669410282)
UPDATE
To expose b as a field:
scala> case class Foo(a: Int)(val b: Int)
defined class Foo
scala> Foo(0)(1).b
res3: Int = 1
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Foo private(x: Int, y: Int) {
def fieldToIgnore: Int = 0
}
object Foo {
def apply(x: Int, y: Int, f: Int): Foo = new Foo(x, y) {
override lazy val fieldToIgnore: Int = f
}
}
// Exiting paste mode, now interpreting.
defined class Foo
defined module Foo
scala> val f1 = Foo(2, 3, 11)
f1: Foo = Foo(2,3)
scala> val f2 = Foo(2, 3, 5)
f2: Foo = Foo(2,3)
scala> f1 == f2
res45: Boolean = true
scala> f1.## == f2.##
res46: Boolean = true
You may override .toString if necessary.
You can override the equals and hasCode methods in a case class
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Person( val name:String, val addr:String) {
override def equals( arg:Any) = arg match {
case Person(s, _) => s == name
case _ => false
}
override def hashCode() = name.hashCode
}
// Exiting paste mode, now interpreting.
scala> Person("Andy", "") == Person("Andy", "XXX")
res2: Boolean = true
scala> Person("Andy", "") == Person("Bob", "XXX")
res3: Boolean = false
If you override toString in the base class it will not be overridden by the derived case classes. Here is an example:
sealed abstract class C {
val x: Int
override def equals(other: Any) = true
}
case class X(override val x: Int) extends C
case class Y(override val x: Int, y: Int) extends C
Than we you test:
scala> X(3) == X(4)
res2: Boolean = true
scala> X(3) == X(3)
res3: Boolean = true
scala> X(3) == Y(2,5)
res4: Boolean = true