Reputation: 1696
I am trying to create a type which will be possible to be updated only once. In the begging the object to have value and it will throw exception if it is accessed. afterwards user can update the object , but other updates will be ignored. this is in order to have kind of state object which update its state once and during a flow, ignore the actual imp of the update method, but i am getting compilation errors of variant, contravariant ... is there a way to solve it?
case class EmptyValueException(message: String = "empty value") extends RuntimeException(message)
trait SingleUpdate[+T] {
def get: T
}
case object EmptyValue extends SingleUpdate[Nothing] {
def get: Nothing = throw EmptyValueException()
}
case class HasValue[+T](value: T) extends SingleUpdate[T] {
def get: T = value
}
object SingleUpdater {
def apply[T]() = new SingleUpdater[T]()
}
class SingleUpdater[+T] {
var single: SingleUpdate[T] = EmptyValue
def get = single.get
def update[T](value: T) = single = HasValue[T](value)
}
Upvotes: 0
Views: 35
Reputation: 15074
Here's an implementation for your intent that compiles happily, albeit it is invariant in its type T
. Also, it ignores updates after the first, which is what I understand your intent to be. It does this silently, which you may wish to change (eg. throw an exception if trying to update again).
case class EmptyValueException(message: String = "empty value") extends RuntimeException(message)
trait SingleUpdate[T] {
def get: T = throw EmptyValueException()
def isSet = false
}
case class HasValue[T](value: T) extends SingleUpdate[T] {
override def get: T = value
override def isSet = true
}
object SingleUpdater {
def apply[T]() = new SingleUpdater[T]()
}
class SingleUpdater[T] {
var single: SingleUpdate[T] = new SingleUpdate[T] {}
def get = single.get
def update(value: T) = if (!single.isSet) single = HasValue[T](value)
}
Example usage:
scala> val su = SingleUpdater[String]
su: SingleUpdater[String] = SingleUpdater@6715f3e8
scala> su.get
EmptyValueException: empty value
at SingleUpdate$class.get(<console>:10)
at SingleUpdater$$anon$1.get(<console>:28)
at SingleUpdater.get(<console>:29)
at .<init>(<console>:10)
at .<clinit>(<console>)
at .<init>(<console>:7)
at .<clinit>(<console>)
...
scala> su.update("Foo")
scala> su.get
res2: String = Foo
scala> su.update("Bar")
scala> su.get
res4: String = Foo
Upvotes: 1