Обойти невозможность создать подкласс зависимого от пути типа
Я ищу способ ограничить вызовы определенных объектов. Для данной транзакционной системы, которая определяет ссылочный тип, тип транзакции и идентификатор:
trait Sys[S <: Sys[S]] {
type Ref[A]
type Tx <: Txn[S]
type ID
}
Я хотел бы иметь возможность смешивать в черту, которая может быть использована для создания изменяемых ссылок:
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)
}
И эталонная фабрика определяется как часть транзакции:
trait Txn[S <: Sys[S]] {
/* private[Mutable] */ def newRef[A](mut: Mutable[S]): S#Ref[A]
def newID: S#ID
}
Теперь проблема в том, что в следующей структуре я могу создавать ссылки с ложным контекстом:
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...
}
Я хотел бы запретить последний звонок. Очевидно, я не могу сделать newRef
в Txn
личное для Mutable
, так как Mutable
не включающий класс Txn
, Я также хотел бы не использовать конфиденциальность пакетов, так как можно легко взломать newRef
путем определения объекта в этом пакете.
В идеале я хотел бы это:
trait Sys[S <: Sys[S]] { trait Mutable }
class MyStruct[S <: Sys[S]] extends S#Mutable { ... }
что бы решить все проблемы. Но это запрещено, так как S
в S#Mutable
"is not a legal prefix for a constructor"
во вселенной скалака....
Спасибо за предложения!
1 ответ
Вы можете поставить определение Txn
в Mutable
объект-компаньон, затем сделайте его закрытым для Mutable
, Не уверен, есть ли дальнейшие последствия, все же.
trait Sys[ S <: Sys[ S ]] {
type Ref[ A ]
type Tx <: Txn[ S ]
type ID
}
object Mutable {
trait Txn[ S <: Sys[ S ]] {
private[Mutable] def newRef[ A ]( mut: Mutable[ S ]) : S#Ref[ A ]
def newID : S#ID
}
}
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 )
}
// Or maybe you could declare type Txn in the package object...
trait Txn[ S <: Sys[ S ]] extends Mutable.Txn[S]
object Foo {
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 ) // doesn't compile...
}
}