I am using phantom types in the type-safe builder pattern to ensure methods are called only once as in the following code sample
sealed trait TBoolean
sealed trait TTrue extends TBoolean
sealed trait TFalse extends TBoolean
class Builder[MethodCalled <: TBoolean] private() {
def foo()(implicit ev: MethodCalled =:= TFalse): Builder[TTrue] = {
new Builder[TTrue]
}
}
object Builder {
def apply() = new Builder[TFalse]()
}
Builder().foo().foo() does not work as required, however I would like to set the error message to something user-readable. At the moment the message is
Multiple markers at this line
– not enough arguments for method foo: (implicit ev: =:=[W.TTrue,W.TFalse])W.Builder[W.TTrue]. Unspecified value parameter ev.
– Cannot prove that W.TTrue =:= W.TFalse.
– Cannot prove that W.TTrue =:= W.TFalse.
Using the type parameters here is a bit of an overkill. Better just return a less capable type from the
foomethod:There is an annotation
implicitNotFoundwhich can be used to customise the error messages, but it needs to be defined with the type that is sought (=:=) not with the use site (foo), so that is a pretty useless construction……unless you create your own replacement for
=:=: