2010-08-13 20 views
16

Ich habe vor kurzem mehr Scala Fragen gesehen (z here, here und here), die für die Verwendung von Proxies genannt, und es kam mehr als einmal in meiner eigenen Arbeit. Die Scala-Bibliothek hat eine Reihe von Proxy-Merkmalen (14, wenn ich richtig gezählt habe).Proxies/Delegierten in Scala

Proxy-Klassen/Merkmale in der Regel eine Menge Text enthalten:

class FooProxy(val self: Foo) extends Foo { 
    // added behavior 
    def mymethod = ... 

    // forwarding methods 
    def method1 = self.method1 
    def method2(arg: String) = self.method2(arg) 
    ... 
} 

trait Foo { 
    def method1: Unit 
    def method2(arg: String): Unit 
} 

Mein erster Gedanke ein Proxy[T] Merkmal zu definieren war, die verwendet werden könnten, wie folgt:

class FooProxy(val self: Foo) extends Proxy[Foo] { 
    // added behavior 
    def mymethod = ... 
} 

wo trait Proxy[T] extends T. Natürlich ist es nicht möglich, das Merkmal Proxy ohne Compiler-Magie zu definieren.

Mein nächster Gedanke war, nach einem Compiler-Plugin zu suchen (eine solche Fähigkeit ist eindeutig nicht im vorhandenen Compiler, oder die Quellen für diese 14 Proxy-Merkmale wären viel kleiner). Sicher genug, ich fand Kevin Wright's AutoProxy plugin. Das Plugin soll ordentlich das Proxy-Problem lösen, zusammen mit anderen Anwendungsfällen (einschließlich dynamischem Mixins):

class FooProxy(@proxy val self: Foo) { ... } 

Leider sieht es aus wie Arbeit auf mich im November (2009) ins Stocken geraten. Also, meine Fragen sind

  1. Gibt es kontinuierliche Arbeit am AutoProxy-Plugin?
  2. Wird dies in den Compiler finden?
  3. Werden andere Ansätze in Betracht gezogen?
  4. Schließlich weist dies auf eine signifikante Schwäche in Scala hin? Wäre es nicht möglich, bei lisp-artigen Makros ein Proxy Merkmal zu definieren?
+0

Eigenschaften können keine Parameter haben. Schlägst du vor, dass sie hinzugefügt werden? Außerdem haben Sie nichts gezeigt, das nicht durch Hinzufügen einer impliziten Konvertierung behoben werden kann. Ist der Vorschlag, dass eine implizite Konvertierung erstellt wird, überflüssig? –

+0

"Traits können keine Parameter haben": dummer Fehler, behoben. –

+0

Implizite Konvertierungen lösen ähnliche Probleme, sind aber nicht immer geeignet (warum würden die EPFL-Leute so viele Proxies in die Scala-Bibliothek aufnehmen?). Zum einen verursachen sie mehr Aufwand als die Delegierung. Zweitens kann eine umfangreiche Verwendung der impliziten Konvertierung die Wartbarkeit/Lesbarkeit beeinträchtigen. –

Antwort

6

Vier Fragen, vier Antworten

  1. Ich bin, obwohl Familie zuerst kommen muss! Außerdem sind andere damit beschäftigt, das generelle Problem mit der Synthese von Methoden in einem Compiler-Plugin zu untersuchen.

  2. Wenn ja, wird es wahrscheinlich in einer anderen Form sein, vielleicht ohne Annotationen zu verwenden.

  3. Ich kenne keine entsprechenden Plugins, obwohl eines der Scala GSOC-Kandidaten-Projekte teilweise auf meinem Autoproxy-Code basierte. Es gibt jedoch eine sehr saubere Lösung, die in den meisten Fällen funktioniert und kein Compiler-Plugin benötigt: Sie definieren eine implizite Konvertierung von FooProxy zu Foo, die einfach das self Member zurückgibt; Das wird dich den größten Teil des Weges dorthin bringen. Die Hauptprobleme bei diesem Ansatz sind, dass es das Leben schwieriger macht, wenn Sie Ihren Code aus Java verwenden müssen, er kann weniger effizient in Bezug auf Geschwindigkeit/Speicher sein, und es ist ein anderes implizites, das Sie beachten müssen.

  4. Der frustrierende Teil ist, dass fast alle der notwendigen Logik in den Compiler bereits verfügbar ist, und es ist für Mixins verwendet, so dass es wirklich soll eine elegante Art und Weise die Aufgabe der Handhabung.

+0

Überprüfen Sie die @Delegate AST-Umwandlung in Groovy. Es ist sehr schön. http://docs.codehaus.org/display/GROOVY/Delegate+Transformation – sourcedelica

5

Adam Warski recently blogged über a Macro-based approach, die in Scala 2.11 arbeiten kann und funktioniert auf jeden Fall mit dem Macro Paradise Compiler-Plugin in Scala 2.10.

erlauben würde, diese Bibliothek Sie

class FooProxy(@delegate wrapped: Foo) extends Foo { 
    // added behavior 
    def mymethod = ... 

    // forwarding methods (generated for you) 
    // def method1 = wrapped.method1 
    // def method2(arg: String) = wrapped.method2(arg) 
} 

Das Projekt in ein schreiben sehr früh ist, Proof-of-concept, Stufe zum Zeitpunkt des Schreibens dieses Artikels, so ist Vorsicht geboten ist.