Обойти невозможность создать подкласс зависимого от пути типа - PullRequest
1 голос
/ 13 декабря 2011

Я ищу способ ограничить вызовы определенных объектов.Учитывая транзакционную систему, которая определяет ссылочный тип, тип транзакции и идентификатор:

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 Ответ

2 голосов
/ 14 декабря 2011

Вы можете поместить определение 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...
    }
}
...