li-raz
li-raz

Reputation: 1696

Creating Single updater object

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

Answers (1)

Shadowlands
Shadowlands

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

Related Questions