2013-05-14 15 views
9

Chciałbym zastosować klasy wartości scala do jednego z moich projektów, ponieważ pozwalają mi wzbogacić pewne prymitywne typy bez wielkiego obciążenia (mam nadzieję) i zachować bezpieczeństwo.Czy dziedziczenie w niejawnych klasach wartości wprowadza narzut?

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 

    } 
} 

Moje pytanie: Czy dziedziczenie Ordered zmusić przydział Pos obiektów ilekroć ich używać (a tym samym wprowadzić wielkie obciążenie), czy nie? Jeśli tak, to czy istnieje sposób na obejście tego?

Odpowiedz

6

Za każdym razem Pos będzie traktowany jako Ordered[Pos], nastąpi przydzielenie. Istnieje kilka przypadków, kiedy przydział musi nastąpić, patrz http://docs.scala-lang.org/overviews/core/value-classes.html#when_allocation_is_necessary.

Więc kiedy robi coś tak prostego jak wywołanie <, dostaniesz przydział:

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

Odpowiednie przepisy zostały (cytat z powyższego artykułu):

Ilekroć klasa wartość jest traktowana jako inny typ, w tym cechę uniwersalną, instancja klasy wartości rzeczywistej musi być utworzona i: Innym przykładem tej reguły jest użycie klasy wartości jako argumentu typu.

Demontaż powyższy fragment kodu potwierdza:

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 

Jak widać mamy dwie instancje „nowej” opcode dla klasy Position$Pos

UPDATE: aby uniknąć przydział w takich przypadkach jak w przypadku uproszczeń, można ręcznie zastąpić każdą metodę (nawet jeśli przesyłają tylko do początkowej implementacji):

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) 

Spowoduje to usunięcie przydziału po wykonaniu przykładu x < y. Jednak nadal pozostawia przypadki, gdy Pos jest traktowane jako Ordered[Pos] (jak po przekazaniu do metody przyjmującej Ordered[Pos] lub Ordered[T] z T będącym parametrem typu). W tym konkretnym przypadku nadal otrzymasz alokację i nie da się tego obejść.

+0

Czy znasz jakiś sposób, aby uniknąć przydziału, aby marka Pos była porównywalna? – peri4n

+0

Sprawdź moją aktualizację. –

+0

Dziękuję bardzo – peri4n