Until 2.8, the only things you could put in a package were classes, traits, and standalone objects. These are by far the most common definitions that are placed at the top level of a package, but version 2.8 of the Scala programming language doesn't limit you to just those. Any kind of definition that you can put inside a class, you can also put at the top level of a package. If you have some helper method you'd like to be in scope for an entire package, go ahead and put it right at the top level of the package.
To do so, put the definitions in a package object. Each package is allowed to have one package object. Any definitions placed in a package object are considered members of the package itself.
An example is shown in the following listings. Assume first a class Fruit and three Fruit objects in a package gardening.fruits:
// in file gardening/fruits/Fruit.scala
package gardening.fruits
case class Fruit(name: String, color: String)
object apple extends Fruit("Apple", "green")
object plum extends Fruit("Plum", "blue")
object banana extends Fruit("Banana", "yellow")
// in file gardening/fruits/package.scala
package gardening
package object fruits {
val planted = List(apple, plum, banana)
def showFruit(fruit: Fruit) {
println(fruit.name +"s are "+ fruit.color)
}
}
Given that definition, any other code in the same package can import the method just like it would import a class. For example, the following object PrintPlanted imports planted and showFruit in exactly the same way it imports class Fruit, using a wildcard import on package gardening.fruits:
// in file PrintPlanted.scala
import gardening.fruits._
object PrintPlanted {
def main(args: Array[String]) {
for (fruit: Fruit <- fruits.planted) {
showFruit(fruit)
}
}
}
Package objects can contain arbitrary definitions, not just variable and method definitions. For instance, they are also frequently used to hold package-wide type aliases and implicit conversions. Package objects can even inherit Scala classes and traits.