解决方法是无法子类化路径依赖类型

时间:2011-12-13 16:35:31

标签: scala subclass private path-dependent-type

我正在寻找一种限制某些对象调用的方法。给定一个事务系统,它定义了一个引用类型,一个事务类型和一个标识符:

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 { ... }

这将解决所有问题。但这是不允许的,因为scalac宇宙中的S S#Mutable中的"is not a legal prefix for a constructor" ....

感谢您的建议!

1 个答案:

答案 0 :(得分:2)

您可以将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...
    }
}