In Scala le classi e i singleton object (e un altro tipo di definizioni, i trait, che verranno presentati a breve) sono organizzati in package. Come in Java, l’appartenenza di una classe a un package è dichiarata all’inizio del file sorgente (l’unità di compilazione) che la contiene mediante la clasuola package. Ad esempio, un file contenente

package pfun.examples

object Hello {
	// ...
}

dichiara che il singleton object Hello appartiene al package pfun.examples.

Ogni membro di un package, cioè ogni risorsa (classe, object o trait) definita a un package, ha un nome completo (fully qualified name) formato dal nome del pacakge seguito dal nome semplice della risorsa stessa (quello che viene specificato quando si definisce la risorsa), separati da un punto. Nell’esempio precedente, l’object definito ha un nome semplice Hello e nome completo pfun.examples.Hello.

Per convenzione, i file sorgente dei package vengono tipicamente organizzati nel file system come in Java: a ogni package corrisponde una directory, e si trattano i caratteri . nei nomi dei package come un’astrazione del separatore di directory; ad esempio, il package pfun.examples corrisponde alla directory pfun/examples. Tecnicamente, però, Scala permette di organizare i sorgenti in modo arbitrario, indipendentemente dai nomi dei package.

Utilizzo

Quando si ha una risorsa definita in un package, ad esempio

package pfun.util

class Rational {
	// ...
}

e la si vuole utilizzare in un altro package, è possibile far riferimento a essa per mezzo del suo nome completo,

object Test {
	val x = new pfun.util.Rational(1, 2)
}

oppure è possibile importarla e riutilizzarla mediante il suo nome semplice (facendo però attenzione a evitare conflitti tra i nomi importati e/o definiti in un file, che avvengono secondo le stesse regole di Java):

import pfun.util.Rational

object Test {
	val x = new Rational(1, 2)
}

Clausole d importazione

L’importazione dei package o dei loro membri avviene tramite la clausola di importazione, import, che è molto più flessibile rispetto all’analoga clausola esistente in Java.

Le importazioni si possono suddividere in due principali forme:

Le clasuole di importazione possono occorrere in qualunque punto del codice sorgente, non solo all’inizio del file come in Java. Ciò permette di importare i membri di un package solo nello scope in cui effettivamete servono. Ad esempio:

object Test {
	import pfun.util.Rational

	// Qui la classe Rational è importata
	val x = new Rational(1, 2);
}

// Qui la classe Rational non è importata

Importazione dei membri di un oggetto