Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Package objects

What are package objects, not so much the concept but their usage?

I've tried to get an example working and the only form I got to work was as follows:

package object investigations {     val PackageObjectVal = "A package object val" }  package investigations {      object PackageObjectTest {         def main(args: Array[String]) {             println("Referencing a package object val: " + PackageObjectVal)         }     } } 

Observations I've made so far are:

package object _root_ { ... } 

is disallowed (which is reasonable),

package object x.y { ... } 

is also disallowed.

It seems that a package object must be declared in the immediate parent package and, if written as above, the brace delimited package declaration form is required.

Are they in common use? If so, how?

like image 690
Don Mackenzie Avatar asked Aug 03 '10 21:08

Don Mackenzie


People also ask

What is a package object?

Scala provides package objects as a convenient container shared across an entire package. Package objects can contain arbitrary definitions, not just variable and method definitions. For instance, they are frequently used to hold package-wide type aliases and implicit conversions.

What is a package Scala?

Package in Scala is a mechanism to encapsulate a group of classes, sub packages, traits and package objects. It basically provides namespace to put our code in a different files and directories. Packages is a easy way to maintain our code which prevents naming conflicts of members of different packages.

What is a Scala object?

In Scala, an object is a named instance with members such as fields and methods. An object and a class that have the same name and which are defined in the same source file are known as companions. Companions has special access control properties, which is covered under Scala/Access modifiers.

Can we import object in Scala?

With Scala you can: Import packages, classes, objects, traits, and methods. Place import statements anywhere. Hide and rename members when you import them.


2 Answers

Normally you would put your package object in a separate file called package.scala in the package that it corresponds to. You can also use the nested package syntax but that is quite unusual.

The main use case for package objects is when you need definitions in various places inside your package as well as outside the package when you use the API defined by the package. Here is an example:

// file: foo/bar/package.scala  package foo  package object bar {    // package wide constants:   def BarVersionString = "1.0"    // or type aliases   type StringMap[+T] = Map[String,T]    // can be used to emulate a package wide import   // especially useful when wrapping a Java API   type DateTime = org.joda.time.DateTime    type JList[T] = java.util.List[T]    // Define implicits needed to effectively use your API:   implicit def a2b(a: A): B = // ...  } 

Now the definitions inside that package object are available inside the whole package foo.bar. Furthermore the definitions get imported when someone outside of that package imports foo.bar._.

This way you can prevent to require the API client to issue additional imports to use your library effectively - e.g. in scala-swing you need to write

import swing._ import Swing._ 

to have all the goodness like onEDT and implicit conversions from Tuple2 to Dimension.

like image 178
Moritz Avatar answered Sep 18 '22 04:09

Moritz


While Moritz's answer is spot on, one additional thing to note is that package objects are objects. Among other things, this means you can build them up from traits, using mix-in inheritance. Moritz's example could be written as

package object bar extends Versioning                            with JodaAliases                            with JavaAliases {    // package wide constants:   override val version = "1.0"    // or type aliases   type StringMap[+T] = Map[String,T]    // Define implicits needed to effectively use your API:   implicit def a2b(a: A): B = // ...  } 

Here Versioning is an abstract trait, which says that the package object must have a "version" method, while JodaAliases and JavaAliases are concrete traits containing handy type aliases. All of these traits can be reused by many different package objects.

like image 45
Dave Griffith Avatar answered Sep 22 '22 04:09

Dave Griffith