I want to implement method chaining like in those questions:
Best practice to implement Scala trait which supports method chaining ;
Scala DSL: method chaining with parameterless methods
However, I want that once a "property" has been used, it cannot be used anymore.
For example lets assume that I have a class "Myclass" for which I want to allow the use of definition "foo" and definition "bar" at most once and I don't care about the final return type. Thus:
val c = new Myclass
c foo //ok !
c foo bar // ok!
c foo foo // refuse to compile
c foo bar foo //refuse to compile
I'm struggling with this problem for a while and my vision starts becoming fuzzy!
I tried to use implicit classes, however, whether they need to parse objects that has not used the associated property, and I can't find how, whether they need to "consume" the property by removing it from the object available property, and, again, I can't find how.
I'm currently searching in the reflection API, but it is still a little obscure for me.
Help would be appreciated! =)
See Phantom Types In Haskell and Scala by James Iry.
You could also use type-safe builder pattern:
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 like this
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
^
here you can ifnd an improved solution :
http://jim-mcbeath.blogspot.fr/2009/09/type-safe-builder-in-scala-part-3.html
(which actually relies on the phantom types)