2013-05-14 12 views
9

Ich möchte scala's Wertklassen auf eines meiner Projekte anwenden, weil sie mir ermöglichen, bestimmte primitive Typen ohne großen Overhead (hoffentlich) anzureichern und typsicher zu bleiben.Vererbt die Vererbung in impliziten Wertklassen einen Overhead?

object Position { 

    implicit class Pos(val i: Int) extends AnyVal with Ordered[Pos] { 

    def +(p: Pos): Pos = i + p.i 

    def -(p: Pos): Pos = if (i - p.i < 0) 0 else i - p.i 

    def compare(p: Pos): Int = i - p.i 

    } 
} 

Meine Frage: das Erbe von Ordered Wird die Zuweisung von Pos Objekte erzwingen, wenn ich sie verwenden (so großen Aufwand einführen) oder nicht? Wenn ja: Gibt es eine Möglichkeit, dies zu umgehen?

Antwort

6

Jedes Mal, wenn Pos als Ordered[Pos] behandelt wird, erfolgt die Zuweisung. Es gibt mehrere Fälle, in denen eine Zuordnung stattfinden muss, siehe http://docs.scala-lang.org/overviews/core/value-classes.html#when_allocation_is_necessary.

Also, wenn etwas so einfach wie der Aufruf von < tun, werden Sie Zuweisungen erhalten:

val x = Pos(1) 
val y = Pos(2) 
x < y // x & y promoted to an actual instance (allocation) 

Die einschlägigen Vorschriften sind (aus dem oben zitierten Artikel):

Jedes Mal, wenn ein Wert Klasse behandelt als ein anderer Typ, einschließlich eines universellen Merkmals, muss eine Instanz der tatsächlichen Wertklasse instanziiert werden und: Eine andere Instanz dieser Regel ist, wenn eine Wertklasse als Typargument verwendet wird.

den obigen Code-Schnipsel Auseinanderbauen bestätigt dies:

0: aload_0 
1: iconst_1 
2: invokevirtual #21     // Method Pos:(I)I 
5: istore_1 
6: aload_0 
7: iconst_2 
8: invokevirtual #21     // Method Pos:(I)I 
11: istore_2 
12: new   #23     // class test/Position$Pos 
15: dup 
16: iload_1 
17: invokespecial #26     // Method test/Position$Pos."<init>":(I)V 
20: new   #23     // class test/Position$Pos 
23: dup 
24: iload_2 
25: invokespecial #26     // Method test/Position$Pos."<init>":(I)V 
28: invokeinterface #32, 2   // InterfaceMethod scala/math/Ordered.$less:(Ljava/lang/Object;)Z 

Wie wir Position$Pos

für die Klasse haben zwei Instanzen des "neuen" opcode tun gesehen werden

UPDATE: um das zu vermeiden Zuweisung in einfachen Fällen wie diesem können Sie jede Methode manuell überschreiben (selbst wenn sie nur an die originale Implementierung weiterleiten):

override def < (that: Pos): Boolean = super.<(that) 
override def > (that: Pos): Boolean = super.>(that) 
override def <= (that: Pos): Boolean = super.<=(that) 
override def >= (that: Pos): Boolean = super.>=(that) 

Dies wird die Zuweisung entfernen, wenn Sie x < y mit Beispiel tun. Dies lässt jedoch immer noch die Fälle, wenn Pos als Ordered[Pos] behandelt wird (wie bei einer Methode, die eine Ordered[Pos] oder eine Ordered[T] mit T ist ein Typparameter) übergeben. In diesem speziellen Fall erhalten Sie immer noch eine Zuweisung und es gibt keine Möglichkeit, dies zu tun.

+0

Sie kennen einen Weg, die Zuordnung zu vermeiden, eine Pos Pos vergleichbar zu machen? – peri4n

+0

Bitte überprüfen Sie mein Update. –

+0

Vielen Dank – peri4n