Given a reference to a case class companion object t and a sequence of parameter seq how can I invoke a new instance of the case class?
I can create a class when I type the number of the parameter by myself.
scala> case class B(n:String,a:Int,b:Int)
defined class B
scala> val t:AnyRef = B
t: AnyRef = B
scala> val m = t.getClass.getMethods.filter{m => m.getName == "apply"}.
filterNot {_.getReturnType.getName == "java.lang.Object"}(0)
m: java.lang.reflect.Method = public B B$.apply(java.lang.String,int,int)
scala> m.invoke(t,"name",1:java.lang.Integer,2:java.lang.Integer)
res99: Object = B(name,1,2)
The problem I couldn't solve is to call invoke with a sequence of arguments like Seq("name",1:java.lang.Integer,2:java.lang.Integer). Any help how to do that is greatly appreciated.
I use scala 2.10.0.
Just found it out by myself (respectively have seen it over here https://stackoverflow.com/a/2060503/55070). It's
method.invoke(t,seq: _*)
Sometimes it really helps to just write it down ;-)
Related
I came from C++ world and new to Scala, and this behavior looks unusual.
class G1[A]( val a : A) {
//val c:A = new A //This gives compile error
def fcn1(b: A): Unit = {
//val aobj = new A // This gives compile error
println(a.getClass.getSimpleName)
println(b.getClass.getSimpleName)
}
}
def fcnWithTP[A](): Unit = {
//val a = new A // This gives compile error
//println(a.getClass.getSimpleName)
}
I am not able to crate a object using the type parameter in a class in a function body or a class body. I am only be able to use it in the function parameter.
What is the reason for this? Is this because of type erasure? At run time, the function does not know what the actual type A is, so it cannot create an object of that type?
What is the general rule for this? Does it that mean the type parameter cannot appear in function body or class definition at all? If they can actually appear, what are the examples?
Yes, you're right that this is because of erasure—you don't know anything about A at runtime that you haven't explicitly asserted about it as a constraint in the method signature.
Type erasure on the JVM is only partial, so you can do some horrible things in Scala like ask for the class of a value:
scala> List(1, 2, 3).getClass
res0: Class[_ <: List[Int]] = class scala.collection.immutable.$colon$colon
Once you get to generics, though, everything is erased, so for example you can't tell the following things apart:
scala> List(1, 2, 3).getClass == List("a", "b", "c").getClass
res1: Boolean = true
(In case it's not clear, I think type erasure is unambiguously a good thing, and that the only problem with type erasure on the JVM is that it's not more complete.)
You can write the following:
import scala.reflect.{ ClassTag, classTag }
class G1[A: ClassTag](val a: A) {
val c: A = classTag[A].runtimeClass.newInstance().asInstanceOf[A]
}
And use it like this:
scala> val stringG1: G1[String] = new G1("foo")
stringG1: G1[String] = G1#33d71170
scala> stringG1.c
res2: String = ""
This is a really bad idea, though, since it will crash at runtime for many, many type parameters:
scala> class Foo(i: Int)
defined class Foo
scala> val fooG1: G1[Foo] = new G1(new Foo(0))
java.lang.InstantiationException: Foo
at java.lang.Class.newInstance(Class.java:427)
... 43 elided
Caused by: java.lang.NoSuchMethodException: Foo.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 43 more
A better approach is to pass in the constructor:
class G1[A](val a: A)(empty: () => A) {
val c: A = empty()
}
And a much better approach is to use a type class:
trait Empty[A] {
def default: A
}
object Empty {
def instance[A](a: => A): Empty[A] = new Empty[A] {
def default: A = a
}
implicit val stringEmpty: Empty[String] = instance("")
implicit val fooEmpty: Empty[Foo] = instance(new Foo(0))
}
class G1[A: Empty](val a: A) {
val c: A = implicitly[Empty[A]].default
}
And then:
scala> val fooG1: G1[Foo] = new G1(new Foo(10101))
fooG1: G1[Foo] = G1#5a34b5bc
scala> fooG1.c
res0: Foo = Foo#571ccdd0
Here we're referring to A in the definition of G1, but we're only making reference to properties and operations that we've confirmed hold or are available at compile time.
Generics are not the same thing as templates. In C++ Foo<Bar> and Foo<Bat> are two different classes, generated at compile time.
In scala or java, Foo[T] is a single class that has with a type parameter. Consider this:
class Foo(val bar)
class Bar[T] {
val foo = new T // if this was possible ...
}
new Bar[Foo]
In C++, (an equivalent of) this would fail to compile, because there is no accessible constructor of Foo that takes no arguments. The compiler would know that when it tried to instantiate a template for Bar<Foo> class, and fail.
In scala, there is no separate class for Bar[Foo], so, at compilation time, the compiler doesn't know anything about T, other than that it is some type. It has no way of knowing whether calling a constructor (or any other method for that matter) is possible or sensible (you can't instantiate a trait for example, or an abstract class), so new T in that context has to fail: it simply does not make sense.
Roughly speaking, you can use type parameters in places where any type can be used (do declare a return type for example, or a variable), but when you are trying to do something that only works for some types, and not for others, you have to make your type param more specific. For example, this: def foo[T](t: T) = t.intValue does not work, but this: def foo[T <: Number](t: T) = t.intValue does.
Well the compiler does not know how to create an instance of type A. You need to either provide a factory function that returns instance of A, or use Manifest which creates instance of A from reflection.
With factory function:
class G1[A](val a:A)(f: () => A) {
val c:A = f()
}
With Manifest:
class G1[A](val a: A)(implicit m: scala.reflect.Manifest[A]) {
val c: A = m.erasure.newInstance.asInstanceOf[A]
}
When using type parameter, usually you will specify more details on the type A, unless you're implementing some sort of container for A that does not directly interact with A. If you need to interact with A, you need some specification on it. You can say A must be a subclass of B
class G1[A <: B](val a : A)
Now compiler would know A is a subclass of B so you can call all functions defined in B on a:A.
Im trying to get the direct super classes / traits of a ClassSymbol. The method baseClasses() does not work for me as it also includes the super super.. types.
The java.lang.Class.getSuperclass() and java.lang.Class.getInterfaces() would actually be sufficient for my use case, but I can't find a way to go from ClassSymbol to java.lang.Class in macro context!
If you use macro - you can't obtain runtime-object Class for class which does not exist (loaded) in compile-time (so you can't have an access to compiling classess from there). But, you could write your own function:
def getDirectBase(a: ClassSymbol) = {
val base = a.baseClasses.toSet - a //`baseClasses` contains `a` itself
val basebase = base.flatMap {
case x: ClassSymbol => x.baseClasses.toSet - x
}
base -- basebase
}
Results (examples obtained using run-time reflection, but compile-time should be same here):
scala> class A
scala> class B extends A
scala> class C extends B
scala> typeOf[C].typeSymbol.asInstanceOf[ClassSymbol].baseClasses
res37: List[reflect.runtime.universe.Symbol] = List(class C, class B, class A, class Object, class Any)
scala> getDirectBase(typeOf[C].typeSymbol.asInstanceOf[ClassSymbol])
res38: scala.collection.immutable.Set[reflect.runtime.universe.Symbol] = Set(class B)
I have a Scala collection that contains objects of different subtypes.
abstract class Base
class A extends Base
class B extends Base
val a1 = new A()
val a2 = new A()
val b = new B()
val s = List(a1, a2, b)
I'd like to filter out all the A objects or the B objects. I can do this easily if I know the object I want to filter on at compile time.
s.filter(_.isInstanceOf[A]) // Give me all the As
s.filter(_.isInstanceOf[B]) // Give me all the Bs
Can I do it if I only know the object type to filter on at runtime? I want to write a function like this.
def filterType(xs:List[Base], t) = xs.filter(_.isInstanceOf[t])
Where t indicates whether I want objects of type A or B.
Of course I can't actually write it this way because of type erasure. Is there an idiomatic Scala way to work around this using type tags? I've been reading the Scala type tag documentation and relevant StackOverflow posts, but I can't figure it out.
This has come up a few times. Duplicate, anyone?
scala> trait Base
defined trait Base
scala> case class A(i: Int) extends Base
defined class A
scala> case class B(i: Int) extends Base
defined class B
scala> val vs = List(A(1), B(2), A(3))
vs: List[Product with Serializable with Base] = List(A(1), B(2), A(3))
scala> def f[T: reflect.ClassTag](vs: List[Base]) = vs collect { case x: T => x }
f: [T](vs: List[Base])(implicit evidence$1: scala.reflect.ClassTag[T])List[T]
scala> f[A](vs)
res0: List[A] = List(A(1), A(3))
Type erasure will destroy any information in type parameters, but objects still know what class they belong to. Because of this, we cannot filter on arbitrary types, but we can filter by class or interface/trait. ClassTag is preferable to TypeTag here.
import scala.reflect.ClassTag
def filterType[T: ClassTag](xs: List[Base]) = xs.collect {
case x: T => x
}
Which we can use like:
scala> filterType[B](s)
res29: List[B] = List(B#42096939)
scala> filterType[Base](s)
res30: List[Base] = List(A#8dbc09c, A#625f8cc7, B#42096939)
This method is safe at run-time if type T is not generic. If there was a class C[T] extends Base we could not safely filter on C[String].
I want to create reflectively a copy of a given object (this object is called root).
For that I need to create an instance of the class of root.
I tried the advice given at
http://docs.scala-lang.org/overviews/reflection/overview.html
but it does not work for objects that have several constructors.
How can I locate the no-arg constructor ?
My guess is that I should use something like asTerm.alternatives.filter(_.typeSignature== ???)) to find the no-arg constructor but I am not sure, is this the correct approach ?
Even if this is the way to go, I have no idea what should go in place of ??? if I am looking for a no-arg constructor ?
In other words, what is the type signature of a no-arg constructor ?
In the code below root is the object whose no-arg constructor I'd like to find.
The code:
val m= runtimeMirror(getClass.getClassLoader)
val rootsMirror: InstanceMirror =m.reflect(root)
val theType: Type =m.reflect(root).symbol.toType
val classSymbol : ClassSymbol =m.reflect(root).symbol
val classMirror:ClassMirror=m.reflectClass(classSymbol)
val constructorMirror: MethodMirror = classMirror.reflectConstructor(
theType.declaration(nme.CONSTRUCTOR).asTerm.alternatives.filter(_.typeSignature== ???))
Something like:
scala> class X(i: Int) { def this() = this(1) }
defined class X
scala> typeOf[X].declarations.filter { s => s.isMethod && {
| val m = s.asMethod
| m.isConstructor && m.paramss.flatten.isEmpty }}
res2: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(constructor X)
A little different, from the types:
scala> res5 filter (_ match { case MethodType(ps, t) if ps.isEmpty => true case _ => false })
res7: Iterable[reflect.runtime.universe.Type] = List(()X)
When you create a case class, the compiler creates a corresponding companion object with a few of the case class goodies: an apply factory method matching the primary constructor, equals, hashCode, and copy.
Somewhat oddly, this generated object extends FunctionN.
scala> case class A(a: Int)
defined class A
scala> A: (Int => A)
res0: (Int) => A = <function1>
This is only the case if:
There is no manually defined companion object
There is exactly one parameter list
There are no type arguments
The case class isn't abstract.
Seems like this was added about two years ago. The latest incarnation is here.
Does anyone use this, or know why it was added? It increases the size of the generated bytecode a little with static forwarder methods, and shows up in the #toString() method of the companion objects:
scala> case class A()
defined class A
scala> A.toString
res12: java.lang.String = <function0>
UPDATE
Manually created objects with a single apply method are not automatically considered as FunctionN:
object HasApply {
def apply(a: Int) = 1
}
val i = HasApply(1)
// fails
// HasApply: (Int => Int)
The reason why case class companion objects implement FunctionN is that before, case classes generated a class and a factory method, not a companion object. When we added extractors to Scala it made more sense to turn the factory method into a full companion object with apply and unapply methods. But then, since the factory method did conform to FunctionN, the companion object needed to conform, too.
[Edit] That said, it would make sense to have companion objects show as their own name, not as "function"
Well, given that target.apply(a1, a2, a3 ... aN) in Scala:
can be sugared by target(a1, a2, a3 ... aN)
is the method which needs to be implemented by FunctionN
it seems natural that a companion object:
object MyClass {
def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}
is really:
object MyClass extends FunctionN[A1, ... , AN, MyClass]{
def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}
So the addition seems to be natural to me (I'm not sure why it seems "odd" to you?). As to whether it actually added anything; well, that is for someone smarter than me!
Aside from oxbow_lakes's reply about the naturalness of it, it can often be useful to have constructors available as first-class functions, particularly in conjunction with Scala collections higher-order functions. For (a trivial) example,
scala> case class Foo(i : Int)
defined class Foo
scala> List(1, 2, 3) map Foo
res0: List[Foo] = List(Foo(1), Foo(2), Foo(3))
Welcome to Scala version 2.8.0.RC3 (Java HotSpot(TM) Client VM, Java 1.6.0_20).
scala> case class CC3(i: Int, b: Boolean, s: String)
defined class CC3
scala> CC3
res0: CC3.type = <function3>
scala> CC3.apply(1, true, "boo!")
res1: CC3 = CC3(1,true,boo!)
scala> CC3(1, true, "boo!")
res2: CC3 = CC3(1,true,boo!)