Artikel

 
Januar 2010 | Artikel

Scala 2.8: Package Scopes und Package Objects

(Link zum Artikel: http://www.it-republik.de/jaxenter/artikel/2816)

Die wichtigsten Neuerungen - Teil 3

Text: Heiko Seeberger
  • Teilen
  • kommentieren
  • empfehlen
  • Bookmark and Share
Wie in der letzten Folge über die überarbeitete Collection Library erwähnt, bringt Scala 2.8 als weitere Neuerung die so genannten Package Objects. Diese werden u.a. verwendet, um den Umstieg von den 2.7-Collections zu erleichtern. Bevor wir uns genauer anschauen, was es damit auf sich hat, werfen wir jedoch erst einen Blick auf eine andere Neuerung im Zusammenhang mit Packages.
Teil 1   Teil 2   

Package Scopes

Anders als in Java, wo nur die Package-Namen in einer hierarchischen Struktur angeordnet sind, können in Scala die Packages selbst verschachtelt werden. Das erkennt man am besten, wenn man die folgende Notation wählt:

  1. package a {
  2. case object A
  3. package b {
  4. case object B {
  5. override def toString = A.toString
  6. }
  7. }
  8. }

In diesem Beispiel befindet sich Package b innerhalb von Package a und daher können wir aus Package b heraus auf das Singleton Object A zugreifen, ohne dieses explizit zu importieren. Das ist in vielen Fällen praktisch und funktioniert gleichermaßen für Scala 2.7 wie 2.8.

Neben dieser etwas speziellen Notation mit geschweiften Klammern bietet Scala auch die von Java bekannte Alternative, in der das package-Statement ohne Klammern vorangestellt wird und sich auf alles unterhalb erstreckt. Obiges Beispiel sieht in Scala 2.7 dann so aus, wobei die beiden Codefragmente auf zwei Dateien verteilt sein sollen:

  1. package a
  2. case object A
  3. package a.b
  4. case object B {
  5. override def toString = A.toString
  6. }

Im unteren Codefragment interpretiert der Scala-Compiler die Deklaration package a.b als zwei verschachtelte Packages. Genau das ändert sich mit Scala 2.8! Wenn wir dieses Beispiel mit dem neuen Scala-Compiler übersetzen, dann erhalten wir beim unteren Codefragment eine Fehlermeldung “... error: not found: value A ...”. Das liegt daran, dass package a.b seit Scala 2.8 nur noch als ein Package interpretiert wird, nicht mehr als zwei verschachtelte Packages.

Warum werden in Scala 2.8 nicht mehr automatisch alle Packages “aufgespannt”? Das liegt daran, dass verschachtelte Packages übergeordnete Packages verdecken können. So verdeckt z.B. package demo.scala alle Typen der Scala-Library. Dieser Sachverhalt erwies sich in einigen Projekten als reales Problem, das nur durch die sehr unschöne “Root-Package-Notation” gelöst werden kann.

Wenn wir das “alte” Verhalten trotz der damit verbundenen Problematik auch mit Scala 2.8 erreichen wollen, dann können wir nun die Package-Deklaration für das zweite Codefragment folgendermaßen schreiben:

  1. package a
  2. package b
  3. case object B {
  4. override def toString = A.toString
  5. }

So werden wieder zwei verschachtelte Packages “aufgespannt”.

Package Objects

Nach dieser Änderung kommen wir zu einer echten Neuerung: Mit Scala 2.8 können wir Packages nicht nur implizit anlegen, indem wir Klassen anlegen, die sich in einem Package befinden, sondern explizit durch so genannte Package Objects. Diese können genau wie Singleton Objects Felder, Methoden und Typen definieren. Ein Beispiel:

  1. package object demo {
  2. implicit def toOption[T](x: T) =
  3. if (x == null) None else Some(x)
  4. }

Hier definieren wir mit den Schlüsselwörtern package object das Package Object demo. Alle Member von Package Objects befinden sich im Scope des entsprechenden Packages, d.h. in unserem Beispiel befindet sich die Methode toOption dadurch im Package demo.

Teil 1   Teil 2   

andere Artikel dieser Serie


Anzeige

Kommentare

Gravatar Hektor 11.02.2010
um 17:20 Uhr
Tolle Serie, deren Artikel ich mit freuden lese. Daher, wann geht es weiter? :-) #zitieren
Gravatar Heiko Seeberger 11.02.2010
um 17:34 Uhr
Danke für das Lob!
Tja, wann geht es weiter? Zum Glück kann ich ein bisschen der EPFL den schwarzen Peter zuschieben, weil sich die Jungs um Martin Odersky mit 2.8 Zeit lassen. Allerdings will ich so ehrlich sein, dass ich selbst auch im Verzug bin :-(
Mal sehen, was ich machen kann ...
#zitieren
Gravatar Antonio R. Rodríguez Santiesteban 04.03.2010
um 20:54 Uhr
Sehr gute Idee mit der Artikelreihe, es ist noch schwer Dokumentation zur 2.8 zu finden.
Ich habe auch eine Frage bzgl. der Package-Objects. Bei dem DSL-Beispiel, heißt das, statt Imports für Objekte der DSL müsste der Client-Code im DSL-Package deklariert werden, also package dsl { Client-Code }?

Danke!
#zitieren
Gravatar Heiko Seeberger 05.03.2010
um 00:33 Uhr
Um Gottes Willen ;-)

Du kannst Deinen Code in ein beliebiges Package geben, musst nur dsl._ importeren.
#zitieren
Gravatar Antonio R. Rodríguez Santiesteban 05.03.2010
um 07:52 Uhr
Also statt import ObjectDSL._ würde man import dsl._ verwenden. Ich sehe nur als Vorteil, dass die DSL-Deklarationen in einem Package, wie im Artikel erwähnt, besser aufgehoben sind. Aber das ist wirklich nur ein kleiner formeller Unterschied ;-), oder? #zitieren
Gravatar Heiko Seeberger 06.03.2010
um 09:57 Uhr
Ja, Package Objects machen hier nur diesen kleinen Unterschied. Wirklich wichtig werden sie z.B., wenn man Typ-Aliase definieren möchte: Bei den Scala 2.8 Collections kommt z.B. das "package object scala" zum Einsatz, um nach wie vor das Arbeiten mit scala.List zu ermöglichen, obwohl List nun unter scala.collection.immutable liegt. #zitieren

Anzeige

zurück zum Seitenanfang