Classes like Function2
usually do not have access to representations of their type arguments, because they are erased at runtime.
However, you could make your own function types which additionally store this info:
import scala.reflect.{ClassTag,classTag}
abstract class PrintedFunction2[A0:ClassTag,A1:ClassTag,B:ClassTag] extends ((A0,A1) => B) {
def apply(a0: A0, a1: A1): B
override def toString() = s"(${classTag[A0]},${classTag[A1]}) => ${classTag[B]}"
}
Note that in your example, you don’t need to explicitly instantiate Function2
, you can use the lambda syntax:
val intFunction: (Int,Int) => Int = (v1, v2) => v1 + v2
In principle, that should also work with our PrintedFunction2
from Scala 2.12 on, thanks to support for SAM type lambdas. But since it requires additional implicit arguments, Scala does not quite seem to handle the lambda syntax.
I managed to make it work with an implicit conversion, though:
implicit def toPF[A0:ClassTag,A1:ClassTag,B:ClassTag](f:(A0,A1)=>B):PrintedFunction2[A0,A1,B] = new PrintedFunction2[A0,A1,B] {
def apply(a0: A0, a1: A1): B = f(a0,a1)
}
Then, in the REPL:
scala> val f: PrintedFunction2[String,Int,String] = (x,y) => x * y
f: PrintedFunction2[String,Int,String] = (java.lang.String,Int) => java.lang.String
scala> println(f)
(java.lang.String,Int) => java.lang.String
scala> f("ok!",3)
res1: String = ok!ok!ok!