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?
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
Related
How to override equals to check value equivalence of functions in specific cases? For example, say we have the following f and g functions
val f = (x: Int) => "worf" + x
val g = (x: Int) => "worf" + x
How could we make assert(f == g) pass?
I tried extending Function1 and implemented equality via generator like so
trait Function1Equals extends (Int => String) {
override def equals(obj: Any): Boolean = {
val b = obj.asInstanceOf[Function1Equals]
(1 to 100).forall { _ =>
val input = scala.util.Random.nextInt
apply(input) == b(input)
}
}
}
implicit def functionEquality(f: Int => String): Function1Equals = (x: Int) => f(x)
but could not get implicit conversion to work on == perhaps due to this. Scalactics's TripleEquals comes close
import org.scalactic.TripleEquals._
import org.scalactic.Equality
implicit val functionEquality = new Equality[Int => String] {
override def areEqual(a: Int => String, b: Any): Boolean =
b match {
case p: (Int => String) =>
(1 to 100).forall { _ =>
val input = scala.util.Random.nextInt
a(input) == p(input)
}
case _ => false
}
}
val f = (x: Int) => "worf" + x
val g = (x: Int) => "worf" + x
val h = (x: Int) => "picard" + x
assert(f === g) // pass
assert(f === h) // fail
How would you go about implementing equality of functions, preferably using regular ==?
First of all, function equality is not a simple topic (spoiler: it cannot be implemented correctly; see e.g. this question and the corresponding answer), but let's assume that your method of "asserting same output for a hundred random inputs" is good enough.
The problem with overriding == is that it's already implemented for Function1 instances. So you have two options:
define a custom trait (your approach) and use ==
define a typeclass with operation isEqual and implement it for Function1
Both options have trade-offs.
In the first case, instead of using standard Scala Function1 trait, you have to wrap each function into your custom trait instead. You did that, but then you tried to implement an implicit conversion that will do the conversion from standard Function1 to Function1Equals for you "behind the scenes". But as you realised yourself, that cannot work. Why? Because there already exists a method == for Function1 instances, so there's no reason for the compiler to kick off the implicit conversion. You have to wrap each Function1 instance into your custom wrapper so that the overridden == gets called.
Here's the example code:
trait MyFunction extends Function1[Int, String] {
override def apply(a: Int): String
override def equals(obj: Any) = {
val b = obj.asInstanceOf[MyFunction]
(1 to 100).forall { _ =>
val input = scala.util.Random.nextInt
apply(input) == b(input)
}
}
}
val f = new MyFunction {
override def apply(x: Int) = "worf" + x
}
val g = new MyFunction {
override def apply(x: Int) = "worf" + x
}
val h = new MyFunction {
override def apply(x: Int) = "picard" + x
}
assert(f == g) // pass
assert(f == h) // fail
Your second option is to keep working with standard Function1 instances, but to use a custom method for equality comparison. This can be easily implemented with a typeclass approach:
define a generic trait MyEquals[A] which will have the needed method (let's call it isEqual)
define an implicit value which implements that trait for Function1[Int, String]
define a helper implicit class which will provide the method isEqual for some value of type A as long as there exists an implicit implementation of MyEquals[A] (and we made sure in the previous step that there is one for MyEquals[Function1[Int, String]])
Then the code looks like this:
trait MyEquals[A] {
def isEqual(a1: A, a2: A): Boolean
}
implicit val function1EqualsIntString = new MyEquals[Int => String] {
def isEqual(f1: Int => String, f2: Int => String) =
(1 to 100).forall { _ =>
val input = scala.util.Random.nextInt
f1(input) == f2(input)
}
}
implicit class MyEqualsOps[A: MyEquals](a1: A) {
def isEqual(a2: A) = implicitly[MyEquals[A]].isEqual(a1, a2)
}
val f = (x: Int) => "worf" + x
val g = (x: Int) => "worf" + x
val h = (x: Int) => "picard" + x
assert(f isEqual g) // pass
assert(f isEqual h) // fail
But as I said, keeping the advantages of first approach (using ==) and second approach (using standard Function1 trait) is not possible. I would argue however that using == isn't even an advantage. Read on to find out why.
This is a good demonstration of why typeclasses are useful and more powerful than inheritance. Instead of inheriting == from some superclass object and overriding it, which is problematic for types we cannot modify (such as Function1), there should instead be a typeclass (let's call it Equal) which provides the equality method for a lot of types.
So if an implicit instance of Equal[Function1] doesn't already exist in the scope, we simply provide our own (like we did in my second snippet) and the compiler will use it. On the other hand, if an implicit instance of Equal[Function1] already does exist somewhere (e.g. in the standard library), it changes nothing for us - we still simply need to provide our own, and it will "override" the existing one.
And now the best part: such typeclass already exists in both scalaz and cats. It is called Equal and Eq respectively, and they both named their equality comparison method ===. This is why I said earlier that I wouldn't even consider being able to use == as an advantage. Who needs == anyway? :) Using scalaz or cats in your codebase consistently would mean that you would rely on === instead of == everywhere, and your life would be simple(r).
But don't count on function equality; that whole requirement is weird and not good. I answered your question pretending that it's fine in order to provide some insights, but the best answer would have been - don't rely on function equality at all.
The Option class has a method named fold(). The docs say:
sealed abstract class Option[+A]
fold[B](ifEmpty: ⇒ B)(f: (A) ⇒ B): B
Returns the result of applying f to this scala.Option's value if the scala.Option is nonempty. Otherwise, evaluates expression ifEmpty.
The docs continue:
This is equivalent to scala.Option map f getOrElse ifEmpty.
But is this really true? I've been told that under certain circumstances, with values of certain types, there are differences, but never with a decent explanation. What exactly are the situations where these two constructions will behave differently and why?
Option.fold is safer than .getOrElse. You can see the definition for .fold below, where both ifEmpty and f are of type B (introduced only after scala 2.10, probably):
#inline final def fold[B](ifEmpty: => B)(f: A => B): B =
if (isEmpty) ifEmpty else f(this.get)
which means you will probably not mess up the data types (exception below):
scala> val data = Option("massive data").fold(-1) { _ => 1 }
data: Int = 1
// but if I try to return different type in either of ifEmpty or f
// compiler will curse me right at my face
scala> val data = Option("massive data").fold(-1) { _ => "Let me get caught by compiler" }
<console>:17: error: type mismatch;
found : String("Let me get caught by compiler")
required: Int
val data = Option("massive data").fold(-1) { _ => "Let me get caught by compiler" }
^
While getOrElse is not as safe, unless you provide the type (supertype B in following definition) manually.
#inline final def getOrElse[B >: A](default: => B): B =
if (isEmpty) default else this.get
which means you can return a different type from getOrElse than what the original value wrapped in Option[A] was.
scala> val data = Option("massive data").map(_ => 1).getOrElse(List("I'm not integer"))
data: Any = 1
// you have to manually mention the type to getOrElse to restrict,
// which is not that smart in my opinion
scala> val data = Option("massive data").map(_ => 1).getOrElse[Int](List("I'm not integer"))
<console>:17: error: type mismatch;
found : List[String]
required: Int
val data = Option("massive data").map(_ => 1).getOrElse[Int](List("I'm not integer"))
^
The interesting thing is you can return unit from getOrElse or fold which can introduce bugs in an application unless you catch it in unit tests.
scala> val data = Option("massive data").fold() { _ => 1 }
data: Unit = ()
scala> val data = Option("massive data").map(_ => 1).getOrElse()
data: AnyVal = 1
As a counterpoint to #prayagupd's answer, fold often invites you to mess up types in a specific way.
The problem is that by Scala's rules, only ifEmpty is used to infer B and then f is checked to be suitable. Which means that using None or Nil as ifEmpty, which is quite common, will lead to their singleton types being used as B instead of Option/List[SomeType], no matter what f returns.
Of course, there are workarounds: specify B explicitly, use Option.empty[SomeType] or None: Option[SomeType] instead of None. Or just use pattern-matching.
Given the following function:
def foo()(implicit count: Int): (String => Seq[String]) = {
s => for (i <- 1 until count) yield s
}
Calling apply() on the result explicitly works:
implicit val count = 5
val x = foo().apply("x") // <- works fine
And setting the result to a val, which you then call as a function, works:
val f: String => Seq[String] = foo()
f("y") // <- works fine
But trying to do it all in one line, without apply, confuses the compiler into thinking you're passing the implicit explicitly:
val z = foo()("z") // type mismatch; found: String("z"), required: Int
Is there a way to do this without either the explicit apply or the intermediate val? For instance, is it possible somehow to move the implicit declaration into the returned anonymous function?
scala> (foo() _)("z")
res10: Seq[String] = Vector(z, z, z, z)
Is there a syntax to allow generic type parameters on function literals? I know I could wrap it in a method such as:
def createLongStringFunction[T](): (T) => Boolean = {
(obj: T) => obj.toString.length > 7
}
but then I end up needing to invoke the method for every type T and getting a new function. I looked through the language reference, and while I see that the function literal syntax is translated by the compiler to an instance of a Functionn object that itself has generic input types, it looks like the compiler magic realizes those parameters at the time of creation. I haven't found any syntax that allows me to, in effect, "leave one or more of the type parameters of Functionn unbound". What I would prefer is something along the lines of:
// doesn't compile
val longStringFunction: [T](T) => Boolean = (obj: T) => obj.toString.length > 7
Does any such thing exist? Or for that matter, what is the explicit type of an eta-expansion function when the method being expanded has generic parameters?
This is a purely contrived and useless example. Of course I could just make the function use Any here.
No, type parameters only apply to methods and not function objects. For example,
def f[T](x: T) = x //> f: [T](x: T)T
val g = f _ //> g: Nothing => Nothing = <function1>
// g(2) // error
val h: Int=>Int = f _ //> h : Int => Int = <function2>
h(2) //> res0: Int = 2
The method f cannot be converted to a polymorphic function object g. As you can see, the inferred type of g is actually Function1[Nothing, Nothing], which is useless. However, with a type hint we can construct h: Function1[Int,Int] that works as expected for Int argument.
As you say, in your example all you're requiring is the toString method and so Any would be the usual solution. However, there is call for being able to use higher-rank types in situations such as applying a type constructor such as List to every element in a tuple.
As the other answers have mentioned, there's no direct support for this, but there's a relatively nice way to encode it:
trait ~>[A[_],B[_]] {
def apply[X](a : A[X]) : B[X]
}
type Id[A] = A //necessary hack
object newList extends (Id ~> List) {
def apply[X](a : Id[X]) = List(a)
}
def tupleize[A,B, F[_]](f : Id ~> F, a : A, b : B) = (f(a), f(b))
tupleize(newList, 1, "Hello") // (List(1), List(Hello))
Since longStringFunction defined as followed is a value, which must have some given type.
val longStringFunction: (T) => Boolean = (obj: T) => obj.toString.length > 7
However, you can reuse a function object with a method:
scala> val funObj: Any => Boolean = _.toString.size > 7
funObj: Any => Boolean = <function1>
scala> def typedFunction[T]: T => Boolean = funObj
typedFunction: [T]=> T => Boolean
scala> val f1 = typedFunction[String]
f1: String => Boolean = <function1>
scala> val f2 = typedFunction[Int]
f2: Int => Boolean = <function1>
scala> f1 eq f2
res0: Boolean = true
This works because trait Function1[-T1, +R] is contravariant of type T1.
In scala, Function values are parametrically monomorphic(while methods are polymorphic)
Shapeless library introduces polymorphic function values which may be mapped over HLists and many more other features.
Please consider the following refs:
http://www.chuusai.com/2012/04/27/shapeless-polymorphic-function-values-1/
http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/
Suppose I have a list of functions as so:
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
(where func1, et al. are defined elsewhere)
I want to write a method that will take a value and match it to the right function based on exact type (match a: A with func1: A => T) or throw an exception if there is no matching function.
Is there a simple way to do this?
This is similar to what a PartialFunction does, but I am not able to change the list of functions in funcList to PartialFunctions. I am thinking I have to do some kind of implicit conversion of the functions to a special class that knows the types it can handle and is able to pattern match against it (basically promoting those functions to a specialized PartialFunction). However, I can't figure out how to identify the "domain" of each function.
Thank you.
You cannot identify the domain of each function, because they are erased at runtime. Look up erasure if you want more information, but the short of it is that the information you want does not exist.
There are ways around type erasure, and you'll find plenty discussions on Stack Overflow itself. Some of them come down to storing the type information somewhere as a value, so that you can match on that.
Another possible solution is to simply forsake the use of parameterized types (generics in Java parlance) for your own customized types. That is, doing something like:
abstract class F1 extends (A => T)
object F1 {
def apply(f: A => T): F1 = new F1 {
def apply(n: A): T = f(n)
}
}
And so on. Since F1 doesn't have type parameters, you can match on it, and you can create functions of this type easily. Say both A and T are Int, then you could do this, for example:
F1(_ * 2)
The usual answer to work around type erasure is to use the help of manifests. In your case, you can do the following:
abstract class TypedFunc[-A:Manifest,+R:Manifest] extends (A => R) {
val retType: Manifest[_] = manifest[R]
val argType: Manifest[_] = manifest[A]
}
object TypedFunc {
implicit def apply[A:Manifest, R:Manifest]( f: A => R ): TypedFunc[A, R] = {
f match {
case tf: TypedFunc[A, R] => tf
case _ => new TypedFunc[A, R] { final def apply( arg: A ): R = f( arg ) }
}
}
}
def applyFunc[A, R, T >: A : Manifest]( funcs: Traversable[TypedFunc[A,R]] )( arg: T ): R = {
funcs.find{ f => f.argType <:< manifest[T] } match {
case Some( f ) => f( arg.asInstanceOf[A] )
case _ => sys.error("Could not find function with argument matching type " + manifest[T])
}
}
val func1 = { s: String => s.length }
val func2 = { l: Long => l.toInt }
val func3 = { s: Symbol => s.name.length }
val funcList = List(func1: TypedFunc[String,Int], func2: TypedFunc[Long, Int], func3: TypedFunc[Symbol, Int])
Testing in the REPL:
scala> applyFunc( funcList )( 'hello )
res22: Int = 5
scala> applyFunc( funcList )( "azerty" )
res23: Int = 6
scala> applyFunc( funcList )( 123L )
res24: Int = 123
scala> applyFunc( funcList )( 123 )
java.lang.RuntimeException: Could not find function with argument matching type Int
at scala.sys.package$.error(package.scala:27)
at .applyFunc(<console>:27)
at .<init>(<console>:14)
...
I think you're misunderstanding how a List is typed. List takes a single type parameter, which is the type of all the elements of the list. When you write
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
the compiler will infer a type like funcList : List[A with B with C => T].
This means that each function in funcList takes a parameter that is a member of all of A, B, and C.
Apart from this, you can't (directly) match on function types due to type erasure.
What you could instead do is match on a itself, and call the appropriate function for the type:
a match {
case x : A => func1(x)
case x : B => func2(x)
case x : C => func3(x)
case _ => throw new Exception
}
(Of course, A, B, and C must remain distinct after type-erasure.)
If you need it to be dynamic, you're basically using reflection. Unfortunately Scala's reflection facilities are in flux, with version 2.10 released a few weeks ago, so there's less documentation for the current way of doing it; see How do the new Scala TypeTags improve the (deprecated) Manifests?.