2010-10-20 6 views
5

Angenommen, ich möchte eine Klasse wie Java Date haben. Sein einziges Datenelement ist ein lange, das seit 1970Overhead "Boxen" primitive Typen über implicits in Scala

die Millisekunden stellt

Würde/Könne es jeden Performance-Vorteil sein, nur eine neue Scala Art machen:

type PrimitiveDate = Long 

Dann können Sie Methoden hinzufügen, indem implizit mit Umwandlung, wie es für Int mit RichInt getan wird. Beinhaltet dieses "Boxen" des primitiven Typs in eine reiche Klasse irgendeinen Overhead (Klassenerzeugung)? Im Grunde könnte man einfach eine statische Methode

def addMonth(date: PrimitiveDate, months: Int): PrimitiveDate = date + 2592000000 * months 

und lassen Sie die Art System Figur heraus, dass es angewandt werden muss, wenn d addMonth 5 in Ihrem Code erscheint.

bearbeiten

Es scheint, dass der Alias ​​Sie erstellen type PrimitiveDate = Long durch Schreiben vom scala Compiler nicht erzwungen wird. Ist das Erstellen einer richtigen Klasse, die Long, die einzige Möglichkeit, einen erzwungenen Typ in Scala zu erstellen?

Wie nützlich sind Sie in der Lage, einen erzwungenen Typalias für primitive Typen zu erstellen?

Antwort

10

Nun, escape analysis sollte bedeuten, dass die jüngsten JVMs müssen nicht tatsächlich Ihre reichen Wrapper erstellen, um die addMonth Methode aufzurufen.

Das Ausmaß, in dem diese in der Praxis tatsächlich auftritt wird natürlich davon abhängen, wie viel von einem Laufzeit Hotspot die JVM entscheiden, dass diese Methoden in der Objekterstellung hinzufügen. Wenn die Escape-Analyse nicht stattfindet, muss die JVM offensichtlich (wie Sie sagen) die Long in einer neuen Instanz der Wrapper-Klasse "boxen". Es beinhaltet keine "Klassenerstellung" - es würde "eine Instanz einer Klasse erstellen" beinhalten. Dieses Beispiel ist kurzlebig würde dann GC-d sofort sein, so dass der Overhead (während klein) ist:

  • Speicherzuweisung für die Instanz
  • GC-ing die Instanz

Diese Es wird offensichtlich nur irgendein Problem sein, wenn Sie auf jeden Fall Code mit sehr niedriger Latenz schreiben, in dem Sie versuchen, die Erstellung von Müll zu minimieren (in einer engen Schleife). Nur du weißt, ob das der Fall ist.

Ob der Ansatz für Sie funktioniert (und die Escape-Analyse zu Hilfe kommt), müssen Sie in der Wildnis testen. Mikro-Benchmarks sind für solche Dinge notorisch schwer zu schreiben.


Der Grund, warum ich wie diese Art Aliase nicht ganz tun Teil einer öffentlichen API ist ist, dass scala sie nicht wirklich erzwingen so streng wie Ich mag würde.Zum Beispiel:

type PrimitiveDate = Long 
type PrimitiveSpeed = Long 
type Car = String 
type Meeting = String 

var maxSpeeds : Map[Car, PrimitiveSpeed] = Map.empty 

//OOPS - much too easy to accidentally send the wrong type 
def setDate(meeting : Meeting, date : PrimitiveDate) = maxSpeeds += (meeting -> date) 
+0

Guter Punkt auf die "erzwingenden Aliase". Das war eine Sache, über die ich mich wunderte. Also gibt es keine Möglichkeit, einen korrekten Typalias für einen primitiven Typ in scala zu erstellen? – ziggystar

+1

@ziggystar - nein gibt es nicht. Ich neige dazu, Typ-Aliase für eines von zwei Dingen zu verwenden: private interne Sachen, wie Kevin unten spricht; Package Object Importe (dh warum "List" scheint immer noch in der "Scala" Paket) –

+0

Ich denke, Miles Sabin kam mit einer eleganten und performanten [Lösung] (https://gist.github.com/milessabin/89c9b47a91017973a35f) 11 Monate nachdem diese Frage gestellt wurde. – itsbruce

4

Sie haben eigentlich keine neue Art im gegebenen Beispiel erstellt, es ist einfach ein Alias ​​für den bereits bestehenden Lang Typen.

Es ist eine Technik, die ich oft verwende, um mit unhandlichen verschachtelten Verbindungen umzugehen. Zum Beispiel würde ich Alias ​​type Grid = Seq[Seq[Int]] um zu vermeiden, Seq[Seq[Int]] für verschiedene Parameter immer wieder zu spezifizieren.

Sie können eine PrimitiveDate Methode nehmen, ganz glücklich ein Long an eine Methode übergeben, obwohl Sie zu tun haben den Vorteil, dass der Code viel besser selbst dokumentiert ist.

case class PrimitiveDate(value:Long) 

und möglicherweise sogar eine implizite bieten Long =>:

Wenn Sie wirklich einen neuen Typ mit erzwungenen Typsicherheit und bequeme Musteranpassung schaffen wollen, ich einen Fall-Klasse verwenden würde PrimitiveDate Konvertierung für Bequemlichkeit.

3

11 Monate nachdem Sie diese Frage gestellt haben, entdeckte Miles Sabin eine sehr einfache, elegante und performante Art, unboxed newtypes in Scala zu erstellen. Im Gegensatz zu Typaliasen werden Typ-Tags erzwungen. Primitive Typen benötigen eine minimale Vorform (eine Zeile pro Primitiv), um eine Spezialisierung zu ermöglichen.

Ein Jahr später fügte er more polished and robust version davon Shapeless hinzu. Das Konzept ist einfach und prägnant genug, um in einem Projekt kopiert zu werden, ohne dass Sie Shapeless hinzufügen müssen, wenn Sie den Rest dieser exzellenten Bibliothek nicht benötigen.

Natürlich wissen sowohl Sie als auch die Leute, die Ihre Frage beantwortet haben, dies, aber es lohnt sich hier hinzuzufügen, weil dies immer noch eine wichtige Frage ist.

+0

Ich nehme an, dass diese unboxed newtypes den Phantomtypen ähnlich sind, die [hier] erwähnt werden (http://stackoverflow.com/questions/6358651/marking-primitive-types-with-phantom-types-in-scala/6360260#6360260), Recht? – ziggystar

Verwandte Themen