My primary question here is: how can I determine, through reflection, that a certain method in a certain class overrides/implements another method in some of its super classes/implemented interfaces?
Basically, if a method m
is defined in a trait I
, I want to treat all methods which get executed by calling i.m(...) forSome { val i :I }
as a single class of abstraction. This seems like the an obvious problem of checking the argument and return types, but it is not so. First, both Java and Scala allow an overriding method to return a subtype of the return type of the overridden method, but, actual Java runtime only recognizes as an override a method with the exact same signature, including the return type. For this reason, both compilers generate a bridge method forwarding to the new implementation as an actual override.
trait Base {
def self :Base
}
class Sub extends Base {
override def self :Sub = this
/** the compiler will generate also:
def self :Base = self :Sub
*/
}
A similar situation arises with generic types: a method, taking an argument of type being an erased type parameter, can be overridden in a class with a concrete implementation:
trait Generic[T] {
def apply(x :T) :Unit
}
class Specific extends Generic[Int] {
override def apply(x :Int) :Unit = ()
/** The compiler generates also:
override def apply(x :Object) :Unit = apply(x.asInstanceOf[Integer].intValue)
*/
}
There may be additional cases I haven’t thought of. Are these methods marked somehow, so they can get recognized by reflection? The generics unfortunately introduce the issue of false positives,
for example Map
inherits map[O](f :A => O) :Iterable[O]
from Iterable[A]
and defines its own map[K1,V1](f :((K, V)) => (K1, V1)) :Map[K1, V1]
which does not override the latter, despite having the same argument list after erasure.