2011-12-16 5 views
15

Если функция принимает структурный тип, он может быть определен как:Почему scala использует метод отражения для вызова по структурному типу?

def doTheThings(duck: { def walk; def quack }) { duck.quack } 

или

type DuckType = { def walk; def quack } 
def doTheThings(duck: DuckType) { duck.quack } 

Затем вы можете использовать эту функцию в следующим образом:

class Dog { 
    def walk { println("Dog walk") } 
    def quack { println("Dog quacks") } 
} 

def main(args: Array[String]) { 
    doTheThings(new Dog); 
} 

Если вы декомпилировать (для Java) классы, сгенерированные scalac для моего примера, вы можете видеть, что аргумент doTheThings имеет тип Object и im использование рефлексии для вызова методов на аргументе (т. duck.quack)

Мой вопрос: почему отражение? Разве не возможно просто использовать анонимный и invokevirtual вместо отражения?

Вот способ перевести (реализовать) структурный тип вызовов для моего примера (синтаксис Java, но точка является байткод):

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();} 
    }); 
    } 
} 

ответ

13

Рассмотрим простое предложение:

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 

Он будет печатать Different ducks по вашему предложению. Вы можете дополнительно его уточнить, но вы просто не можете сохранить обратное равенство без изменений с помощью прокси.

Возможным решением было бы использовать шаблон типа типа, но для этого потребуется передать другой параметр (даже если он неявный). Тем не менее, это быстрее. Но это в основном из-за хромоты скорости отражения Java. Хотелось бы надеяться, что обработчики методов обойдутся проблемой скорости. К сожалению, Scala не планирует отказываться от Java 5, 6 и 7 (которые не имеют обработок методов) в течение некоторого времени ...

+0

Я не получил последнее предложение, не могли бы вы объяснить? –

+0

@ om-nom-nom 'invokevirtual' нет на JVM 1.5 и 1.6, поэтому Scala не может положиться на него. Scala 2.10 фактически осудит JVM 1.5, но еще некоторое время, прежде чем Scala сможет воспользоваться преимуществами присутствующих только на JVM 1.7. –

+0

@ Daniel C. Sobral: Я предполагаю, что вы использовали 'invokedynamic' вместо' invokevirtual' в своем последнем комментарии –

10

В дополнение к вашим методам реализации прокси-объекта на структурном типе это также должны иметь соответствующие сквозные реализации всех методов для Any (equals, hashCode, toString, isInstanceOf, asInstanceOf) и AnyRef (getClass, wait, notify, notifyAll и synchronized). Хотя некоторые из них были бы простыми, некоторые из них были бы почти невозможны. В частности, все перечисленные методы являются «окончательными» на AnyRef (для совместимости и безопасности Java) и поэтому не могут быть правильно реализованы вашим прокси-объектом.

+1

@ Daniel C.Собрал и Дэйв Гриффит: Оба ваших ответа приемлемы. Поэтому мне пришлось бросить монету, чтобы официально принять ее. –

 Смежные вопросы

  • Нет связанных вопросов^_^