2009-12-16 5 views
17

Wenn ich eine Methode zu einer Klasse in Scala hinzufügen will, muß ich, wie etwas tun:warum „pimp my Bibliothek“ Verstehen in Scala auf diese Weise definiert wurde

class RichFoo(f: Foo) { 
    def newMethod = f.bar() 
} 
object RichFoo { 
    implicit def foo2Rich(f: Foo) = new RichFoo(f) 
} 

Dann in der Schöpfung f.newMethod resultieren aus RichFoo Instanz und rufen Sie die Methode auf.

Ich versuche zu verstehen, warum es nicht ähnlich Ruby definiert wurde:

override class Foo { 
    def newMethod = bar 
} 

Der Compiler an dieser Definition aussehen kann, und eine FooOverride Klasse mit statischer Methode newMethod erstellen, die einen Parameter vom Typ Foo bekommt und ruft seine Balkenmethode auf. So implementiert Scala Eigenschaften. Ich muss immer noch das Paket mit der Foo-Überschreibung importieren, um es zu verwenden.

Es scheint weniger Tippen zu erfordern, erfordert nicht, dass ich Namen erfinde, und hat eine bessere Leistung (keine Methode aufrufen und ein Objekt erstellen). Alles, was die implizite Konvertierungsmethode tut, kann innerhalb der zusätzlichen Methode erfolgen.

Ich bin mir sicher, ich habe etwas verpasst und möchte einen Einblick in was bekommen.

+0

Does Rubin wirklich heraus ausführen Scala in diesem Fall oder spekulieren Sie, dass eine offene Implementierungsklasse Kann so schnell wie ein geschlossen gemacht werden? –

+3

Ich schlage eine Fassade vor, die so aussieht, als würde man eine Klasse wieder öffnen, ruft aber tatsächlich nur statische Methoden auf. Der scala-Compiler macht solche Dinge ständig (Eigenschaften werden mit statischen Methoden zu einer Schnittstelle und einer Klasse kompiliert). Ich spekuliere, dass es weniger codiert und schneller ist als die aktuelle implizite Methode – IttayD

Antwort

13

Es gibt auch andere Verwendungen für implizite Konvertierungen andere als nur das Idiom „meine Bibliothek pimpen“, es ist also nicht wirklich ein Fall von "Warum haben sie das nicht gemacht?", aber "warum haben sie das nicht auch gemacht?". Sicherlich kann ich keinen Grund sehen, warum eine Syntax der Erweiterungsmethode nicht hinzugefügt werden könnte, wie Sie vorschlagen, und es wäre wahrscheinlich etwas sauberer, aber es gibt nicht viel dringendes Bedürfnis dafür, da die Sprache bereits einen Weg unterstützt, den gleichen Effekt zu erzielen .

-Update Oktober 2011:

Es gibt einen neuen Vorschlag Syntax Zucker für diesen Anwendungsfall hinzuzufügen: http://scala.github.com/sips/pending/implicit-classes.html

+0

Ich denke, du hast Recht. – IttayD

+1

Ihre Antwort ist korrekt. Ich möchte darauf hinweisen, dass es tatsächlich eine experimentelle Erweiterung des Scala-Compilers (Scala-virtualisiert) gibt, die das Hinzufügen von Methoden zu bestehenden Klassen durch das Schreiben von weniger Code unterstützt. Suchen Sie nach "def infix_ +" in dieser Klasse, um einige Beispiele zu finden : https://github.com/TiarkRompf/virtualization-lms-core/blob/e11ee5c5c9eb5d00e38927f5f1722bc956e8615d/src/ppl/StringOps.scala Scala virtualisierten unterstützt auch andere Funktionen, für die die beste Referenz (wenn auch nicht vollständig) ist dies : https://github.com/tiarkrompf/scala-virtualized/wiki – Blaisorblade

8

Wie verhindern Sie, dass diese Methode den Bereich eingibt, ohne dass explizit importiert und benannt werden muss? In der Tat, wie kann ein Programm wissen, welche Methoden hinzugefügt wurden, ohne dies zu tun?

Wenn Sie drei verschiedene Bibliotheken verwenden, von denen zwei dem dritten auf inkompatible Weise Methoden hinzufügen, wie würden Sie das umgehen, ohne die Kontrolle zu übernehmen?

Abgesehen davon ist eine bessere Leistung nicht möglich, da JVM es nicht erlaubt, eine vorhandene Klasse zu ändern. Im besten Fall könnten Sie den Vorteil haben, dass Sie keinen Namen erfinden müssen und weniger auf Kosten der Kontrolle verlieren müssen, was getan wird.

Als abschließende Bemerkung, wenn Sie kurz möchten, können Sie tun:

implicit def fooBar(f: Foo) = new { def newMethod = bar } 
+2

Ich importiere stattdessen Foo's Override. Ich schlug nicht vor, die Klasse zu ändern. Ich schlug vor, dass foo.bar in com.my.package.Foo.bar (foo) konvertiert wird. Ihr letztes Beispiel bedeutet newMethod durch Reflexion aufrufen – IttayD

+4

Die 'neue {...} Ding ist ein Strukturtyp. Seien Sie vorsichtig damit: Ihre Methoden werden über Reflektion aufgerufen, was sie langsam macht. Siehe http://stackoverflow.com/questions/3119580/scala-eqivalent-of-csharps-extension-methods/3119671#3119671 – Jesper

Verwandte Themen