scala - resolucion - sismica de reflexion geofisica
¿Por qué scala utiliza la reflexión para llamar método en tipo estructural? (2)
Además de los métodos de implementación de su objeto proxy en el tipo estructural, también debería tener implementaciones de transferencia adecuadas de todos los métodos en Any (es igual a hashCode, toString, isInstanceOf, asInstanceOf) y AnyRef (getClass, wait, notificar , notificar a todos, y sincronizado). Si bien algunos de estos serían sencillos, algunos serían casi imposibles de acertar. En particular, todos los métodos enumerados son "finales" en AnyRef (para compatibilidad con Java y seguridad) y, por lo tanto, su objeto proxy no puede implementarlos correctamente.
Si la función acepta el tipo estructural, se puede definir como:
def doTheThings(duck: { def walk; def quack }) { duck.quack }
o
type DuckType = { def walk; def quack }
def doTheThings(duck: DuckType) { duck.quack }
Luego, puedes usar esa función de la siguiente manera:
class Dog {
def walk { println("Dog walk") }
def quack { println("Dog quacks") }
}
def main(args: Array[String]) {
doTheThings(new Dog);
}
Si descompila (en Java) las clases generadas por scalac para mi ejemplo, puede ver que el argumento de doTheThings
es de tipo Object
y la implementación usa la reflexión para llamar a métodos en el argumento (es decir, duck.quack
)
Mi pregunta es ¿por qué la reflexión? ¿No es posible usar solo anónimo e invocador en lugar de reflexión?
Esta es la forma de traducir (implementar) las llamadas de tipo estructural para mi ejemplo (sintaxis Java, pero el punto es el código de bytes):
class DuckyDogTest {
interface DuckType {
void walk();
void quack();
}
static void doTheThing(DuckType d) {
d.quack();
}
static class Dog {
public void walk() { System.out.println("Dog walk"); }
public void quack() { System.out.println("Dog quack"); }
}
public static void main(String[] args) {
final Dog d = new Dog();
doTheThing(new DuckType() {
public final void walk() { d.walk(); }
public final void quack() { d.quack();}
});
}
}
Considera una proposición simple:
type T = { def quack(): Unit; def walk(): Unit }
def f(a: T, b: T) =
if (a eq b) println("They are the same duck!")
else println("Different ducks")
f(x, x) // x is a duck
Se imprimirían Different ducks
bajo su propuesta. Podría refinarlo aún más, pero no puede mantener intacta la igualdad referencial utilizando un proxy.
Una posible solución sería utilizar el patrón de clase de tipo, pero eso requeriría pasar otro parámetro (aunque sea implícito). Aún así, es más rápido. Pero eso se debe principalmente a la cojera de la velocidad de reflexión de Java. Con suerte, los manejadores de métodos evitarán el problema de la velocidad. Desafortunadamente, Scala no está programado para renunciar a Java 5, 6 y 7 (que no tienen controladores de métodos) por algún tiempo ...