Jus12
Jus12

Reputation: 18024

How to handle different package names in different versions?

I have a 3rd party library with package foo.bar

I normally use it as:

import foo.bar.{Baz => MyBaz}

object MyObject {
  val x = MyBaz.getX // some method defined in Baz
}

The new version of the library has renamed the package from foo.bar to newfoo.newbar. I have now another version of my code with the slight change as follows:

import newfoo.newbar.{Baz => MyBaz}

object MyObject {
  val x = MyBaz.getX // some method defined in Baz
}

Notice that only the first import is different. Is there any way I can keep the same version of my code and still switch between different versions of the 3rd party library as and when needed?

I need something like conditional imports, or an alternative way.

Upvotes: 2

Views: 231

Answers (2)

Travis Brown
Travis Brown

Reputation: 139038

The other answer is on the right track but doesn't really get you all the way there. The most common way to do this kind of thing in Scala is to provide a base compatibility trait that has different implementations for each version. In my little abstracted library, for example, I have the following MacrosCompat for Scala 2.10:

package io.travisbrown.abstracted.internal

import scala.reflect.ClassTag

private[abstracted] trait MacrosCompat {
  type Context = scala.reflect.macros.Context

  def resultType(c: Context)(tpe: c.Type)(implicit
    tag: ClassTag[c.universe.MethodType]
  ): c.Type = {
    import c.universe.MethodType

    tpe match {
      case MethodType(_, res) => resultType(c)(res)
      case other => other
    }
  }
}

And this one for 2.11:

package io.travisbrown.abstracted.internal

import scala.reflect.ClassTag

private[abstracted] trait MacrosCompat {
  type Context = scala.reflect.macros.whitebox.Context

  def resultType(c: Context)(tpe: c.Type): c.Type = tpe.finalResultType
}

And then my classes, traits, and objects that use the macro reflection API can just extend MacrosCompat and they'll get the appropriate Context and an implementation of resultType for the version we're currently building (this is necessary because of changes to the macros API between 2.10 and 2.11).

(This isn't originally my idea or pattern, but I'm not sure who to attribute it to. Probably Eugene Burmako?)

If you're using SBT, there's special support for version-specific source trees—you can have a src/main/scala for your shared code and e.g. src/main/scala-2.10 and src/main/scala-2.11 directories for version-specific code, and SBT will take care of the rest.

Upvotes: 2

Arseniy Zhizhelev
Arseniy Zhizhelev

Reputation: 2401

You can try to use type aliases:

package myfoo

object mybar {
  type MyBaz = newfoo.newbar.Baz
  // val MyBaz = newfoo.newbar.Baz // if Baz is a case class/object, then it needs to be aliased twice - as a type and as a value
}

And then you may simply import myfoo.mybar._ and replace the object mybar to switch to different version of the library.

Upvotes: 0

Related Questions