What might be the straightforward way to make a class's private member accessible in a self typed trait bearing that class's type?
It seems that protected
does the job, but AFAIK that allows access also for subclasses, which is kind of too wide an access scope bundling to me, unless, traits with self types and subclasses are more closely related than I imagine. Can you shed some light on this?
Code fiddle:
trait CakeLayer {
self: A =>
println(a)
}
class A {
protected val a: Int = 3
}
To me, the semantics of a self-typed trait are very different from those of a subclass, when I use it for the cake pattern: I'd not like any subclass to have access, but only the specific self typed trait.
I can think of a somewhat convoluted way of enforcing this - it might inspire you (or someone else) to a more workable solution:
trait CakeLayer {
self: A =>
def funcToRun(a: Int) = println(a)
runFuncOnA
}
class A {
implicit val me: this.type = this
private val a: Int = 3
protected def runFuncOnA(implicit cl: CakeLayer) = cl.funcToRun(a)
}
This enforces that any subclass of A that doesn't extend CakeLayer trying to call runFuncOnA won't compile:
scala> val aa = new A // Doesn't call 'runFuncOnA' - OK
aa: A = A@6a997956
scala> val aa = new A { runFuncOnA } // Doesn't extend CakeLayer - bad!
<console>:28: error: could not find implicit value for parameter cl: CakeLayer
val aa = new A { runFuncOnA }
^
scala> val aWithCL = new A with CakeLayer // Extends CakeLayer, so calling 'runFuncOnA' is OK here:
3
aWithCL: A with CakeLayer = $anon$1@59bf1b79
Basically, the trait calls on the parent class to in-turn call back a particular method defined on the trait, passing the private value.