Abstract private fields in Scala trait -
i happened find it's not allowed have abstract private fields in trait, is,
trait a1 { //private val a: int // not allowed protected val b: int // ok }
and seems right such thing abstract class, if private fields constructor parameters, is,
abstract class a2 (private val i: int) // ok
so guess trait doesn't have constructor parameters, there's no way initialize them, therefore no abstract private fields allowed.
if "protected", subclass can initialize them using pre-initialized fields. approach allows subclass see these fields.
what if want initialize them , hide them afterwards, in following example?
object holding { trait trick { protected val seed: int // can't private final def magic: int = seed + 123 } trait new_trick extends trick { def new_magic: int = magic + 456 def the_seed: int = seed // [1] } def play: new_trick = new { val seed = 1 } new_trick def show_seed(t: new_trick): int = t.the_seed // [2] }
i don't want able see seed, is, [2] (and [1]) shouldn't allowed. there way trait that?
as @randall , @pagoda_5b have pointed out, question doesn't make sense. luckily @régis , @axel22 have turned interesting question , provided pattern solving it.
a simple way keep val private while allowing sub-traits initalize define private initialize value returned protected method. sub-traits can define protected method change initial value, cannot access value itself. change this:
trait { protected val foo: bar }
into:
trait { private val foo: bar = initfoo protected def initfoo: bar }
now, trait a
can access val foo
. sub-traits can set initial value of foo
definint initfoo
, cannot access foo
itself:
trait b extends { protected def initfoo: bar = ??? }
obviously, initfoo
still accessible sub-traits. not problem if initfoo
creates new instance everytime (in other words, factory), might interested in making instance private a
without being concerned having sub-traits being able create new instances of bar
(irrespective of whether new instances equals foo
per equals
method).
but if concern (and in case seed
fo type int
, want hide value , not reference), can use additional trick allow sub-traits define initfoo
prevent them (and sub-traits) being able call it. trick is, let's face it, pretty awful such simple need, illustrates nice pattern advanced access control. credits goes standard library authors idea (see http://www.scala-lang.org/api/current/index.html#scala.concurrent.canawait).
trait { // "permit" call fooinit. instance can instantiate inita abstract class inita private[this]() // unique "permit" private implicit def inita: inita = null private def foo: int = fooinit protected def fooinit( implicit init: inita ): int } trait b extends { protected def fooinit( implicit init: inita ): int = 123 }
now, if b
tries call initfoo
, compiler complain not find implicit of type inita
(the unique such instance a.inita
, accesible in a
) .
as said, it's bit awful , package private solution given axel22 easier alternative (although won't prevent defining sub-traits inside same package yours, defeating access restriction).
Comments
Post a Comment