See Phantom Types in Haskell and Scala by James Irie .
You can also use a line type template:
trait TTrue trait TFalse @annotation.implicitNotFound(msg = "Cannot call same method twice.") sealed abstract class =^=[From, To] object =^= { private val singleton_=^= = new =^=[Any, Any]{} implicit def tpEquals[A]: A =^= A = singleton_=^=.asInstanceOf[A =^= A] } class Myclass[TFoo, TBar, TBuz] private(){ def foo(implicit e: TFoo =^= TFalse) = new Myclass[TTrue, TBar, TBuz] def bar(implicit e: TBar =^= TFalse) = new Myclass[TFoo, TTrue, TBuz] def buz(implicit e: TBuz =^= TFalse) = new Myclass[TFoo, TBar, TTrue] } object Myclass{ def apply() = new Myclass[TFalse, TFalse, TFalse] }
to be used in this way
scala> Myclass().foo.bar.buz res0: Myclass[TTrue,TTrue,TTrue] = Myclass@12ac706a scala> Myclass().bar.buz.foo res1: Myclass[TTrue,TTrue,TTrue] = Myclass@1e69dff6 scala> Myclass().foo.buz.foo <console>:12: error: Cannot call same method twice. Myclass().foo.buz.foo ^
senia source share