Invoke all methods on a Scala object using reflection - scala

Given the following object
object functions {
type MyOutput = String
def f1: MyOutput = "res1"
def f2: MyOutput = "res2"
def f3(foo: String): Boolean = foo.equals("bar")
def f4(in:String): MyOutput = in+"res4"
}
Is it possible to call all methods on this object, which the returned type is of MyOutput type?
Currenly I tried to use reflection for this, but had no luck with it.
import scala.reflect.runtime.universe._
val m = runtimeMirror(getClass.getClassLoader)
val instanceMirror = m.reflect(typeOf[functions.type])
val classSymbol = m.classSymbol(functions.getClass)
val methods = classSymbol.info.members.filter(_.isMethod)
methods.foreach({
method =>
if (method.info.resultType.toString.contains("MyOutput")) {
println(method.name.toString)
val methodm = instanceMirror.reflectMethod(method.asMethod)
methodm()
}
})
This is the error
scala.ScalaReflectionException: expected a member of class UniqueSingleType, you provided method

val instanceMirror = m.reflect(functions)
should be instead of
val instanceMirror = m.reflect(typeOf[functions.type])
This was the mistake because it's functions that is an instance, not typeOf[functions.type] (which is UniqueSingleType as written in the error).
Also there can be some improvements.
val classSymbol = m.classSymbol(functions.getClass)
val methods = classSymbol.info.members.filter(_.isMethod)
can be now replaced with
val methods = typeOf[functions.type].decls.toList.filter(_.isMethod)
since you know the object functions at compile time (so you don't need .classSymbol) and you're interested in the object methods rather than methods of its parents (so this is .decls rather than .members).
It's better to replace
method.info.resultType.toString.contains("MyOutput")
with
method.info.resultType =:= typeOf[String]
(aka method.info.resultType =:= typeOf[functions.MyOutput]) in order not to rely on a work with raw strings.
In methodm() you should provide arguments for the method:
methodm(...here...)

Related

In scala reflection, how to resolve concrete type member?

I have a program that can yield an abstract TypeTag when executed:
class TypeResolving extends FunSpec {
import org.apache.spark.sql.catalyst.ScalaReflection.universe._
val example = new Example
it("can convert") {
val t1 = implicitly[TypeTag[example.T]]
println(t1)
}
}
object TypeResolving {
class Example {
type T = Map[String, Int]
}
val example = new Example
}
The execution results in:
TypeTag[TypeResolving.this.example.T]
Since in this case example.T is already defined, I would also like to get the actual TypeTag:
TypeTag[Map[String,Int]]
How do I get there?
Try dealias
def dealias[T, T1](typeTag: TypeTag[T]): TypeTag[T1] = backward(typeTag.tpe.dealias)
val typeTag = implicitly[TypeTag[TypeResolving.example.T]] //TypeTag[TypeResolving.example.T]
val typeTag1 = dealias(typeTag) //TypeTag[scala.collection.immutable.Map[String,Int]]
val typeTag2 = implicitly[TypeTag[Map[String, Int]]] //TypeTag[Map[String,Int]]
val typeTag3 = dealias(typeTag2) //TypeTag[scala.collection.immutable.Map[String,Int]]
typeTag1 == typeTag3 //true
How to get the aliased type of a type alias in scala runtime?
Get a TypeTag from a Type? (backward is from here)

How to use the ReadWriter for parameterized types

I am trying to migrate to the latest version of upickle 0.7.1. Where I had previously passed around implicit Readers and Writers I believe I must now use a single ReadWriter and explicitly define them in a companion object for any case classes I want to serialize. But I cannot figure out how this works for a parameterized type. So for example say I had the following before upgrading (from 0.4.4):
trait OldTrait[T] {
implicit val evr: Reader[T]
implicit val evw: Writer[T]
def save(t: T): String = write(t)
def restore(str: String): T = read[T](str)
}
class MyOldClass[T](implicit val evr: Reader[T], val evw: Writer[T]) extends OldTrait[T] {
}
case class Request[T](msg: T)
val c1 = new MyOldClass[Request[Int]]
The above code compiled fine for me. To migrate this code I have tried the following:
trait NewTrait[T] {
implicit val evrw: ReadWriter[T]
}
class MyNewClass[T](implicit val evrw: ReadWriter[T]) extends NewTrait[T] {
}
object Request {
implicit val rw: ReadWriter[Request[_]] = macroRW
}
val c2 = new MyNewClass[Request[Int]]
But this will not compile for me. I get the following errors:
Don't know how to derive type ...Request[] implicit val rw:
ReadWriter[Request[]] = macroRW
... could not find implicit value for parameter evrw:
upickle.default.ReadWriter[Request[Int]]
...not enough arguments for constructor MyNewClass: (implicit evrw:
upickle.default.ReadWriter[Request[Int]])MyNewClass[Request[Int]].
Unspecified value parameter evrw. val c2 = new
MyNewClass[Request[Int]]
What would be the correct approach to migrating the old code?
Not tested, but I would expect you need
implicit def rw[T: ReadWriter]: ReadWriter[Request[T]] = macroRW
So e.g. because there is a ReadWriter[Int], there's also a ReadWriter[Request[Int]].
(I would be very surprised if this doesn't work, but you can certainly do it manually instead of macroRW in this case.)

Is it possible to write typeclass with different implementations?

This is a follow-up to my previous question
Suppose I have a trait ConverterTo and two implementations:
trait ConverterTo[T] {
def convert(s: String): Option[T]
}
object Converters1 {
implicit val toInt: ConverterTo[Int] = ???
}
object Converters2 {
implicit val toInt: ConverterTo[Int] = ???
}
I have also two classes A1 and A2
class A1 {
def foo[T](s: String)(implicit ct: ConverterTo[T]) = ct.convert(s)
}
class A2 {
def bar[T](s: String)(implicit ct: ConverterTo[T]) = ct.convert(s)
}
Now I would like any foo[T] call to use Converters1 and any bar[T] call to use Converters2 without importing Converters1 and Converters2 in the client code.
val a1 = new A1()
val a2 = new A2()
...
val i = a1.foo[Int]("0") // use Converters1 without importing it
...
val j = a2.bar[Int]("0") // use Converters2 without importing it
Can it be done in Scala ?
Import Converters in the class.
class A1 {
import Converters1._
private def fooPrivate[T](s: String)(implicit ct: ConverterTo[T]) = ct.convert(s)
def fooShownToClient[T](s: String) = fooPrivate(s)
}
Then use the method, that is shown to client
val a1 = new A1()
a1.fooShownToClient[Int]("0")
Now the client is unaware of the convertors.
If you have a situation where you need more local control; You can just opt to pass the implicit parameters explicitly:
val i = a1.foo("0")(Converters1.toInt)
val j = a2.foo("0")(Converters2.toInt)
It really depends on what you want. If you want to select a particular implementation without polluting local scope, do it like this (or introduce a new scope). mohit's solution works well if the classes need a particular implementation (although in that case, there's no real point in declaring this dependency as implicit anymore).

Get the companion object instance of a inner modul with the Scala reflection API

I implemented the code mentioned in Get companion object instance with new Scala reflection API (code from here https://gist.github.com/xeno-by/4985929).
object Reflection {
def getCompanionObject(caseclassinstance:Product):Any = {
import scala.reflect.runtime.{currentMirror => cm}
val classSymbol = cm.classSymbol(caseclassinstance.getClass)
val moduleSymbol = classSymbol.companionSymbol.asModule
val moduleMirror = cm.reflectModule(moduleSymbol)
moduleMirror.instance
}
}
This works fine for any standard class of case classes. Unfortunately in some classes of the project I get an Exception: scala.ScalaReflectionException: object Tensor is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror The exception is pretty clear, so I tried to change my code as follows:
object Reflection {
def getCompanionObject(caseclassinstance:Product):Any = {
import scala.reflect.runtime.{currentMirror => cm}
val classSymbol = cm.classSymbol(caseclassinstance.getClass)
val moduleSymbol = classSymbol.companionSymbol.asModule
val instanceMirror = cm.reflect(caseclassinstance)
val moduleMirror = instanceMirror.reflectModule(moduleSymbol)
moduleMirror.instance
}
}
But now I get a scala.ScalaReflectionException: expected a member of class Tensor, you provided object Prototype2.SPL.SPL_Exp.Tensor and I did not find out how to change the code to fix this. Any help is greatly appreciated!
Update: I provide some code for better reproducibility:
scala> trait SPL {
| case class Tensor()
| }
defined trait SPL
scala> val s = new SPL {}
s: SPL = $anon$1#165f5a4
scala> val t = s.Tensor()
t: s.Tensor = Tensor()
scala> object Reflection { /* as in the first code snippet*/}
defined module Reflection
scala> Reflection.getCompanionObject(t)
scala.ScalaReflectionException: object Tensor is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror
...
scala> object Reflection { /* as in the second code snippet*/}
defined module Reflection
scala> Reflection.getCompanionObject(t)
scala.ScalaReflectionException: expected a member of class Tensor, you provided object SPL.Tensor
...
You should have an instance of module. You can get mirror for Tensor symbol only from mirror of Spl.
trait Spl {
case class Tensor(s: String)
}
val spl = new Spl {}
val t = spl.Tensor("T")
// mirror for module spl
val moduleMirror = cm.reflect(spl)
// class symbol for Tensor
val instanceSymbol = cm.classSymbol(t.getClass)
// symbol for companion object
val companionSymbol = instanceSymbol.companionSymbol.asModule
// mirror for companion object symbol in spl module mirror
val companionMirror = moduleMirror.reflectModule(companionSymbol)
scala> companionMirror.instance
res0: Any = Tensor
You could get an instance of Spl using a bit of ugly magic:
val outer =
t.
getClass.
getFields.
find(_.getName == """$outer""").
get.
get(t)
You should not do so until you can.
def getCompanionObject(t: Product):Any = {
import scala.reflect.runtime.{currentMirror => cm}
val outerField = t.getClass.getFields.find(_.getName == """$outer""")
val moduleMirror = outerField.map{ _.get(t) }.map{ cm.reflect(_) }
val instanceSymbol = cm.classSymbol(t.getClass)
val companionSymbol = instanceSymbol.companionSymbol.asModule
val companionMirror =
moduleMirror.
map{ _.reflectModule(companionSymbol) }.
getOrElse{ cm.reflectModule(companionSymbol) }
companionMirror.instance
}

How to use scala reflection API to get all contained classes

I got this kind of class:
trait ThirdParty { def invoke = println("right") }
trait WeatherIcon { def invoke = println("wrong") }
class MyClass {
object objA extends ThirdParty
object objB extends WeatherIcon
}
How can I use the Scala reflection API to iterate through the contained objects and invoke a method if it is an instance of a ThirdParty class?
Based on what soc wrote, I got this:
import scala.reflect.runtime.universe._
val members = typeOf[MyClass].members.filter(_.typeSignature match {
case tpe if tpe <:< typeOf[ThirdParty] => true
case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] => true
case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] => true
case _ => false
})
Let me explain the pattern match. The type of a val or an object can be compared directly, but functions have a slightly different type. Here I'm matching against methods with no parameter lists, and methods with a zero-arity parameter list.
There are some differences here compared to soc's answer. First, I use members instead of declarations. That returns inherited members as well as those that are declared on MyClass itself.
Second, I check that it is a value member, as opposed to a type member. You can only invoke methods on values, so it looked a reasonable restriction, though maybe unnecessary. upd. The isValue method is no longer available in 2.10.0-RC1, so I removed the check.
Finally, I use <:< instead of checking each parent for equality.
Now, to the invocation. I'm going to change the code above since invocation depends on what kind of member you have, so we'd best do filtering and invocation at the same time. I'm going to change from members to nonPrivateMembers as well, assuming that's what is wanted. upd. nonPrivateMembers is no longer available in 2.10.0-RC1, use filter(!_.isPrivate) if necessary.
And I'll also avoid using typeOf, which won't work with mirrors on the REPL. upd. In 2.10.0-RC1 typeOf is working finely, but I'll keep the skeleton of the implementation unchanged.
All of the above is basically concerned with the structure of things: what the members of a type are, what kind of members they are, and so on. When you want to use this stuff, in you need mirrors.
Whenever you have a symbol or a type for something -- a class, method, obj, etc -- you act on that thing through a mirror. To act (reflectively) on an instance of an object, you need an instance mirror. To act on a method, you need a method mirror, and so on.
So let's try to build a functon to do what's requested:
import scala.reflect.runtime.universe._
def invoke[Target : TypeTag](obj: Any): Seq[Target] = {
val mirror = runtimeMirror(obj.getClass.getClassLoader)
val insMirror = mirror reflect obj
val originType = insMirror.symbol.typeSignature
val targetType = typeTag[Target].tpe
val members = originType.members
val result = members collect (member => member.typeSignature match {
case tpe if tpe <:< typeOf[ThirdParty] =>
if (member.isModule)
(insMirror reflectModule member.asModule).instance
else
(insMirror reflectField member.asTerm).get
case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] =>
(insMirror reflectMethod member.asMethod).apply()
case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] =>
(insMirror reflectMethod member.asMethod).apply()
})
result.map(_.asInstanceOf[Target]).toSeq
}
Note that nested modules cannot be recovered with Scala 2.10.0-M4 -- that should be possible with M5 or RC1. To test this code with M4, replace the module code with null.
Here's a sample:
scala> class MyClass {
object objA extends ThirdParty
object objB extends WeatherIcon
val aVal = new ThirdParty {}
val bVal = new WeatherIcon {}
def aDef = new ThirdParty {}
def bDef = new WeatherIcon {}
def anotherDef() = new ThirdParty {}
def yetAnotherDef() = new WeatherIcon {}
}
defined class MyClass
scala> invoke[ThirdParty](new MyClass)
res88: Seq[ThirdParty] = List(MyClass$$anon$5#c250cba, MyClass$$anon$3#54668d90, MyClass$$anon$1#18d8143a, null)
I can't offer a complete solution, but maybe this is a start:
import reflect.runtime.universe._
val myClassType = typeOf[MyClass] // Get the type of McClass
val thirdPartyType = typeOf[ThirdParty] // Get the type of ThirdParty
val methodToInvoke = newTermName("invoke")
val declsOfMyClass = myClassType.declarations // Get the declarations of MyClass
val subtypesOfThirdParty =
declsOfMyClass.filter(_.typeSignature.parents.contains(thirdPartyType))
val methodsToInvoke = // Now we have the methods.
subtypesOfThirdParty.map(tps => tps.typeSignature.member(methodToInvoke))
// TODO: Invoke!
I guess there is a much more straight-forward way than this.