2

I'm trying to invoke a function using the scala reflection api in v2.11.6:

import scala.reflect.runtime.{universe => ru}

def f(i: Int) = i + 2

val fn: Any = (f _)
val ref = ru.runtimeMirror(ru.getClass.getClassLoader).reflect(fn)
val apply = ref.symbol.typeSignature.member(ru.TermName("apply"))

When using ref.reflectMethod(apply.asMethod) it complains about multiple alternatives to apply on ref. Examining apply.asTerm.alternatives reveals two methods, one with signature (x$1: Int)Int and the other with (v1: T1)R. Calling

ref.reflectMethod(apply.asTerm.alternatives(1).asInstanceOf[ru.MethodSymbol])(1)

(with the second alternative) returns the correct result (3). However calling the first alternative raises an exception: java.lang.IllegalArgumentException: object is not an instance of declaring class

What are those alternatives and how can I make sure to always invoke the proper one? There also seems to be a problem with invoking a Function2 or higher with this method, so what is the correct way to do it?

Pyetras
  • 1,492
  • 16
  • 21

1 Answers1

3

The reason why there are overloaded apply methods is that Function1 is @specialized for primitive types.

I don't know if there is a better way to distinguish them, but the following seems to work, looking for the alternative whose argument erases to AnyRef (instead of a primitive such as Int):

def invoke(fun1: Any, arg1: Any): Any = {
  import scala.reflect.runtime.{universe => ru}
  val mirror  = ru.runtimeMirror(ru.getClass.getClassLoader)
  val ref     = mirror.reflect(fn)
  val applies = ref.symbol.typeSignature.member(ru.TermName("apply"))
  val syms    = apply.alternatives.map(_.asMethod)  
  val sym     = syms.find { m =>
    m.paramLists match {
      case (arg :: Nil) :: Nil 
        if arg.asTerm.typeSignature.erasure =:= ru.typeOf[AnyRef] => true
      case _ => false
    }
  } getOrElse sys.error("No generic apply method found")
  ref.reflectMethod(sym)(arg1)
}

// Test:
val fn: Any = (i: Int) => i + 2
invoke(fn, 1)  // res: 3
0__
  • 66,707
  • 21
  • 171
  • 266