I am looking for a way to restrict invocations of certain objects. Given a transactional system which defines a reference type, a transaction type, and an identifier:
trait Sys[S <: Sys[S]] {
type Ref[A]
type Tx <: Txn[S]
type ID
}
I would like to be able to mix in a trait that can be used to create mutable references:
trait Mutable[S <: Sys[S]] {
def id: S#ID
protected final def newRef[A](implicit tx: S#Tx): S#Ref[A] =
tx.newRef[A](this)
}
And the reference factory is defined as part of the transaction:
trait Txn[S <: Sys[S]] {
/* private[Mutable] */ def newRef[A](mut: Mutable[S]): S#Ref[A]
def newID: S#ID
}
Now, the problem is, in the following structure I can create references with false contexts:
def newStruct[S <: Sys[S]](cross: Mutable[S])(implicit tx: S#Tx) =
new Mutable[S] {
val id = tx.newID
val allowed = newRef[Int]
val forbidden = tx.newRef[Int](cross) // shouldn't compile...
}
I would like to disallow the last call. Obviously, I cannot make newRef in Txn private to Mutable, because Mutable is not an enclosing class of Txn. I also would like not to use package privacy, as one can easily break into newRef by defining an object in that package.
Ideally I would like this:
trait Sys[S <: Sys[S]] { trait Mutable }
class MyStruct[S <: Sys[S]] extends S#Mutable { ... }
which would solve all the problems. But this is disallowed, since S in S#Mutable "is not a legal prefix for a constructor" in scalac’s universe….
Thanks for suggestions!
You can put the definition of
TxninMutable‘s companion object, then make it private toMutable. Not sure if there are further implications, though.