2013-05-14 13 views
9

Voglio applicare le classi di valore di scala a uno dei miei progetti perché mi consentono di arricchire determinati tipi primitivi senza grandi spese generali (spero) e di rimanere al sicuro.L'ereditarietà delle classi di valore implicite introduce un sovraccarico?

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 

    } 
} 

La mia domanda: Sarà l'eredità del Ordered forzare l'assegnazione di Pos oggetti ogni volta che li uso (quindi introdurre grande testa) o no? Se è così: c'è un modo per aggirare questo?

risposta

6

Ogni volta che Pos verrà considerato come Ordered[Pos], l'allocazione avverrà. Ci sono diversi casi in cui l'allocazione deve avvenire, vedere http://docs.scala-lang.org/overviews/core/value-classes.html#when_allocation_is_necessary.

Così quando si fa qualcosa di semplice come chiamare <, si otterrà allocazioni:

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

Le norme rilevanti sono (citato dal suddetto articolo):

Ogni volta che viene trattata una classe di valori come un altro tipo, incluso un tratto universale, un'istanza della classe valore reale deve essere istanziata e: Un'altra istanza di questa regola è quando una classe valore viene utilizzata come argomento tipo.

Smontaggio del frammento di codice di cui sopra conferma:

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 

Come si può vedere noi abbiamo due istanze del "nuovo" codice operativo per la classe Position$Pos

UPDATE: per evitare il l'allocazione in casi semplici come questo, è possibile sovrascrivere manualmente ciascun metodo (anche se inoltrano solo all'implementazione originlal):

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) 

Questo rimuoverà l'allocazione quando si esegue x < y dall'esempio. Tuttavia, questo lascia i casi quando Pos viene considerato come un Ordered[Pos] (come quando è passato a un metodo prendendo uno Ordered[Pos] o uno Ordered[T] con T che è un parametro di tipo). In questo caso particolare, riceverai comunque un'assegnazione e non c'è modo di aggirarla.

+0

Sei a conoscenza di un modo per evitare l'assegnazione di una marca Pos comparabile? – peri4n

+0

Si prega di controllare il mio aggiornamento. –

+0

Grazie mille – peri4n

Problemi correlati