5
votes

I'm in a situation where I have a need to mix in a trait defined in another package. To assist with testing, a protected method in this trait is package qualified. Here is an example:

package A {
  trait X {
    protected[A] def method(arg: Int)
  }
}

package B {
  class Y extends A.X {
    protected[A] def method(arg: Int) { }
  }
}

Compiling this with scalac 2.9.1 yields:

test.scala:9: error: A is not an enclosing class
    protected[A] def method(arg: Int) { }

Changing the "protected[A]" in class Y to any other access modifier results in this:

test.scala:9: error: overriding method method in trait X of type (arg: Int)Unit;
 method method has weaker access privileges; it should be at least protected[A]
    override protected def method(arg: Int) { }

My question is this: Assuming the definition of trait X can not change, is there any change to class Y that would allow it to extend trait X? (while retaining some level of 'protected' access)

If this is not possible, are there any other recommended design strategies to work around this? (other than making 'method' public)

1
I should add that I'm trying to answer the simple question of whether this is impossible by design, such that the only (simple) way to fix is to change 'protected[A]' to 'public'. It just seems like a sub-class regardless of package should be able to access? or not?nu11ptr
It is looking like the 'right' solution here is to break up the definition of class Y into a class and a trait. I'll put the trait in a sub-package of A, define 'method' there, and then mix it in with class Y. In the real world, A is 'marketdata' and B is 'broker', so it makes sense when we finally have a broker instance that is also a data provider to split off this functionality, put it in a sub-pkg of marketdata, and mix it in. This is probably a better design anyway, as they are two completely different concerns (order handling vs. market data).nu11ptr

1 Answers

2
votes

I ended up solving this with an adapter. While I can't change the original trait, I can add another in the same package (but for other reasons it wouldn't make sense to put the class Y in that package). The 'adapterMethod' in class Y is qualified to package B as an experiment, but most likely this is unnecessary for my use case. The following compiles in scala 2.9.1:

package A {
  trait X {
    protected[A] def method(arg: Int)
  }

  trait PackageAdapter {
    protected[A] def method(arg: Int) { adapterMethod(arg) }

    protected def adapterMethod(arg: Int)
  }
}

package B {
  class Y extends A.X with A.PackageAdapter {
    protected[B] def adapterMethod(arg: Int) { }
  }
}

I'm not crazy about this solution, but it isn't so bad. Class Y is a bit of an exception case as the rest of the classes that use trait X are in package A (class Y must be in package B for many other reasons). Any better ideas?