d money d money - 1 year ago 186
Scala Question

Aliasing Scala package objects

I'm developing a library that depends on another. The dependency has a

package object
that I'd like to alias into my own package domain, to 'hide' the underlying library from the users of the one I'm developing, for potential later reimplementation of that library. I've tried a couple things, including

object functions {
def identity(a: Any): Any = a
def toUpper(s: String): String = s.toUpperCase
object renamedfunctions {
import functions._

This compiles but
import renamedfunctions._
brings nothing into scope. I've also tried extending the backing object, but scala objects are un-extendable. Does anyone know of a way to accomplish what I'm trying to do without forking the underlying library?

Answer Source

It is not possible to do this with Scala packages, in general. Usually, you would only alias a package locally within a file:

import scala.{ math => physics }

scala> physics.min(1, 2)
res6: Int = 1

But this doesn't do what you ask. Packages themselves aren't values or types, so you cannot assign them as such. These will fail:

type physics = scala.math
val physics = scala.math

With a package object, you can grab ahold of it's concrete members, but not the classes within. For example:

scala> val physics = scala.math.`package`
physics: math.type = scala.math.package$@42fcc7e6

scala> physics.min(1, 2)
res0: Int = 1

But using objects or types that belong to the traditional package won't work:

scala> scala.math.BigDecimal(1)
res1: scala.math.BigDecimal = 1

scala> physics.BigDecimal(1)
<console>:13: error: value BigDecimal is not a member of object scala.math.package

Ok, so what should you do?

The reason you're even considering this is that you want to hide the implementation of which library you're using so that it can easily be replaced later. If that's the case, what you should do is hide the library within another interface or object (a facade). It doesn't mean you need to forward every single method and value contained within the library, only the one's you're actually using. This way, when it comes to migrating to another library, you only need to change one class, because the rest of the code will only reference the facade.

For example, if we wanted to use min and max from scala.math, but later wanted to replace it with another library that provided a more efficient solution (if such a thing exists), we could create a facade like this:

object Math {
    def min(x: Int, y: Int): Int = scala.math.min(x, y)
    def max(x: Int, y: Int): Int = scala.math.max(x, y)

All other classes would use Math.min and Math.max, so that when scala.math was replaced, they could remain the same. You could also make Math a trait (sans implementations) and provide the implementations in a sub-class or object (say ScalaMath), so that classes could inject different implementations.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download