Tuesday, May 13, 2014

Package objects

http://stackoverflow.com/questions/3400734/package-objects
http://www.naildrivin5.com/scalatour/wiki_pages/PackageObjects


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:
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 = // ...

}


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.

No comments: