How to get Scala function parameters / return type?

I have a function and I want to get its parameter types and return type for use in Scala macros.

scala> val fn = (a: String, b: Double) => 123 fn: (String, Double) => Int = <function2> scala> fn.getClass res1: Class[_ <: (String, Double) => Int] = class $anonfun$1 

In the above example, the parameter types and return type are already printed on both lines, but I don’t know how to get them. Even with toString I would be stuck with parts of the <function2> and the class $anonfun$1 sign = - otherwise a bit ugly string analysis could be done.

I found that MethodSymbolApi offers a way to extract this information for methods, but it seems that this may not help in this particular case.

I'm currently studying AST parsing (as part of scala.meta ) to extract information, but I think this question will seem simple enough to cover the standard reflection library, although I have not been able to find what I want there. Any ideas?

Edit based on @johanandren's answer:

I have not yet found a more accurate way to extract them from TypeTag / Type, but this already works. :)

 scala> val fn = (a: String, b: Double) => 123 scala> import scala.reflect.runtime.{universe => ru} scala> def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T] scala> getTypeTag(fn).tpe.toString.split(" => ") res179: Array[String] = Array((String, Double), Int) 
+5
source share
2 answers

getClass is part of the Java reflection API, which does not quite understand the Scala types, you should look at the Scala Reflection API. It should start, http://docs.scala-lang.org/overviews/reflection/overview.html

Not sure, but I think TypeTag for function type is what you want.

+3
source

For completeness only, when you are in the Scala REPL, you can access the type as:

 scala> val fn = (a: String, b: Double) => 123 fn: (String, Double) => Int = <function2> scala> :type fn (String, Double) => Int 

At runtime, Scala compiler will not have complete type information. Thus, it forms a code fragment fn (also searches for its own symbol tables). https://github.com/scala/scala/blob/v2.10.5/src/compiler/scala/tools/nsc/interpreter/ILoop.scala#L449

Then it passes it to the compiler, which then binds the type information to the implicit evidence type.

(explained here I want to get the type of a variable at runtime )

 scala> import scala.reflect.runtime.universe.{TypeTag, typeTag} import scala.reflect.runtime.universe.{TypeTag, typeTag} scala> def getTypeTag[T: TypeTag](obj: T) = typeTag[T] getTypeTag: [T](obj: T)(implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.TypeTag[T] 

Now we have evidence that will give us accurate type information:

 scala> getTypeTag(fn) res0: reflect.runtime.universe.TypeTag[(String, Double) => Int] = TypeTag[(String, Double) => Int] scala> val targs = res0.tpe.typeArgs targs: List[reflect.runtime.universe.Type] = List(String, Double, Int) 

Now we can easily access these types:

 scala> val (in, out) = (ta.init, ta.last) in: List[reflect.runtime.universe.Type] = List(String, Double) out: reflect.runtime.universe.Type = Int scala> println(s"INPUTS: $in") INPUTS: List(String, Double) scala> println(s"OUTPUT: $out") OUTPUT: Int 
+3
source

All Articles