Implementing observer pattern - scala

I recently started learning Scala and started a little project to create a simple roguelike game. However, I'm stuck at trying to implement the observer pattern.
This answer touches the subject, but I can't figure out how to make it work. Below is the code from the answer linked above. I'm mostly puzzled by the "this: S =>" part of the code, I suppose I should have some kind of a function there, but I'm not sure. I would like to have it return a tuple from the class that will extend the Subject trait.
trait Observer[S] {
def receiveUpdate(subject: S);
}
trait Subject[S] {
this: S =>
private var observers: List[Observer[S]] = Nil
def addObserver(observer: Observer[S]) = observers = observer :: observers
def notifyObservers() = observers.foreach(_.receiveUpdate(this))
}

See Steve's answer about the self type and for another code example.
Here is some sample code using an observer. The ObservedAccount is the Subject that is observed by an AccountReporter observer.
trait Observer[S] {
def receiveUpdate(subject: S);
}
trait Subject[S] {
this: S =>
private var observers: List[Observer[S]] = Nil
def addObserver(observer: Observer[S]) = observers = observer :: observers
def notifyObservers() = observers.foreach(_.receiveUpdate(this))
}
class Account(initialBalance: Double) {
private var currentBalance = initialBalance
def balance = currentBalance
def deposit(amount: Double) = currentBalance += amount
def withdraw(amount: Double) = currentBalance -= amount
}
class ObservedAccount(initialBalance: Double) extends Account(initialBalance) with Subject[Account] {
override def deposit(amount: Double) = {
super.deposit(amount)
notifyObservers()
}
override def withdraw(amount: Double) = {
super.withdraw(amount)
notifyObservers()
}
}
class AccountReporter extends Observer[Account] {
def receiveUpdate(account: Account) =
println("Observed balance change: "+account.balance)
}
Let's see it in action:
scala> val oa = new ObservedAccount(100.0)
oa: ObservedAccount = ObservedAccount#3f947e20
scala> val ar = new AccountReporter
ar: AccountReporter = AccountReporter#6ea70a98
scala> oa.addObserver(ar)
scala> oa.deposit(40.0)
Observed balance change: 140.0
scala> oa.withdraw(40.0)
Observed balance change: 100.0

Building on Brian's answer: I find it unnecessary to have a separate Observer[S] trait, simply S => Unit is good enough:
trait Subject[S] {
this: S =>
private var observers: List[S => Unit] = Nil
def addObserver(observer: S => Unit) = observers = observer :: observers
def notifyObservers() = observers.foreach(_.apply(this))
}
class Account(initialBalance: Double) {
private var currentBalance = initialBalance
def balance = currentBalance
def deposit(amount: Double) = currentBalance += amount
def withdraw(amount: Double) = currentBalance -= amount
}
class ObservedAccount(initialBalance: Double) extends Account(initialBalance)
with Subject[Account] {
override def deposit(amount: Double) = {
super.deposit(amount)
notifyObservers()
}
override def withdraw(amount: Double) = {
super.withdraw(amount)
notifyObservers()
}
}
class AccountReporter {
def receiveUpdate(account: Account) =
println("Observed balance change: " + account.balance)
}
object Main extends App {
println("start app")
val oa = new ObservedAccount(100.0)
val ar = new AccountReporter
oa.addObserver(ar.receiveUpdate _)
oa.deposit(40.0)
oa.deposit(60.0)
println("stop app")
}
/**
a copy paste observer pattern scala mini-app
sbt run should produce:
[info] Running app.Main
start app
Observed balance change: 140.0
Observed balance change: 200.0
stop app
*/

Sorry to answer a question with a question. Have you read your answer here or the more interesting answer here and here? Someone should compile a reading list, if they haven't. Did Coursera have a reading list?

this is a Scala self-type ( see http://www.scala-lang.org/node/124 ). It expresses a requirement that all concrete implementations of the trait Subject[S] must also conform to the type S. That is, every observable Subject[S] is itself an S.
This is reasonable for the Observer pattern -- it is the observable subject itself that should have registration and notify methods, so the subject consistent with an observer of S should itself be an S.

Related

In Scala, how to deal with heterogeneous list of the same parameterized type

I have an array of Any (in real life, it's a Spark Row, but it's sufficient to isolate the problem)
object Row {
val buffer : Array[Any] = Array(42, 21, true)
}
And I want to apply some operations on its elements.
So, I've defined a simple ADT to define a compute operation on a type A
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
Given that I have a list of all operations and I know which operation is to apply to each element, let's use these operations.
object GenericsOp {
import Row._
val ops = Seq(Count, Exist)
def compute() = {
buffer(0) = ops(0).compute(ops(0).cast(buffer(0)))
buffer(1) = ops(0).compute(ops(0).cast(buffer(1)))
buffer(2) = ops(1).compute(ops(1).cast(buffer(2)))
}
}
By design, for a given op, types are aligned between cast and combine. But unfortunately the following code does not compile. The error is
Type mismatch, expected: _$1, actual: AnyVal
Is there a way to make it work ?
I've found a workaround by using abstract type member instead of type parameter.
object AbstractOp extends App {
import Row._
trait Op {
type A
def compute(a: A) : A
}
case object Count extends Op {
type A = Int
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op {
type A = Boolean
override def compute(a: Boolean): Boolean = a
}
val ops = Seq(Count, Exist)
def compute() = {
val op0 = ops(0)
val op1 = ops(1)
buffer(0) = ops(0).compute(buffer(0).asInstanceOf[op0.A])
buffer(1) = ops(0).compute(buffer(1).asInstanceOf[op0.A])
buffer(2) = ops(1).compute(buffer(2).asInstanceOf[op1.A])
}
}
Is there a better way ?
It seems that your code can be simplified by making Op[A] extend Any => A:
trait Op[A] extends (Any => A) {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
def apply(a: Any): A = compute(cast(a))
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i)(buffer(i))
}
println(buffer.mkString("[", ",", "]"))
}
}
Since it's asInstanceOf everywhere anyway, it does not make the code any less safe than what you had previously.
Update
If you cannot change the Op interface, then invoking cast and compute is a bit more cumbersome, but still possible:
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i) match {
case op: Op[t] => op.compute(op.cast(buffer(i)))
}
}
println(buffer.mkString("[", ",", "]"))
}
}
Note the ops(i) match { case op: Opt[t] => ... } part with a type-parameter in the pattern: this allows us to make sure that cast returns a t that is accepted by compute.
As a more general solution than Andrey Tyukin's, you can define the method outside Op, so it works even if Op can't be modified:
def apply[A](op: Op[A], x: Any) = op.compute(op.cast(x))
buffer(0) = apply(ops(0), buffer(0))

Is it possible to pass values from two instances of the same Scala class

Say I have this situation
class Pipe {
var vel = 3.4
var V = 300
var a = 10.2
var in = ???
var TotV = V+in
var out = TotV*a/vel
}
val pipe1 = new Pipe
val pipe2 = new Pipe
The in variable is were my problem is, what i'd like to do is get the out variable from pipe1 and feed that in as the in variable for pipe 2 effectively to join the two pipes but I cant figure out if this is even possible in the same class. So I can do it manually but need to know if its possible to do in the class.
pipe2.in = pipe1.out
my attempted fix was to add an ID field then try and use that to reference an instance with a higher id field but that doesnt seem doable. ie
class Pipe(id:Int) {
var vel = 3.4
var V = 300
var a = 10.2
var in = Pipe(id+1).out //this is the sticking point, I want to reference instances of this class and use their out value as in value for instances with a lower ID
var TotV = V+in
var out = TotV*a/vel
}
any help would be appreciated
You can do this by defining a companion object for the class and passing in the upstream pipe as an optional parameter to the factory method, then extracting its in value and passing it to the class constructor, as follows:
object Pipe {
def apply(upstreamPipe: Option[Pipe]): Pipe = {
val inValue = upstreamPipe match {
case Some(pipe) => pipe.out
case None => 0 // or whatever your default value is
new Pipe(inValue)
}
You would then call
val pipe1 = Pipe(None)
val pipe2 = Pipe(Some(pipe1))
Unfortunately your question is not clear now. Under certain assumptions what you describe looks like what is now called "FRP" aka "Functional Reactive Programming". If you want to do it in a serious way, you probably should take a look at some mature library such as RxScala or Monix that handle many important in the real world details such as error handling or scheduling/threading and many others.
For a simple task you might roll out a simple custom implementation like this:
trait Observable {
def subscribe(subscriber: Subscriber): RxConnection
}
trait RxConnection {
def disconnect(): Unit
}
trait Subscriber {
def onChanged(): Unit
}
trait RxOut[T] extends Observable {
def currentValue: Option[T]
}
class MulticastObservable extends Observable with Subscriber {
private val subscribers: mutable.Set[Subscriber] = mutable.HashSet()
override def onChanged(): Unit = subscribers.foreach(s => s.onChanged())
override def subscribe(subscriber: Subscriber): RxConnection = {
subscribers.add(subscriber)
new RxConnection {
override def disconnect(): Unit = subscribers.remove(subscriber)
}
}
}
abstract class BaseRxOut[T](private var _lastValue: Option[T]) extends RxOut[T] {
private val multicast = new MulticastObservable()
protected def lastValue: Option[T] = _lastValue
protected def lastValue_=(value: Option[T]): Unit = {
_lastValue = value
multicast.onChanged()
}
override def currentValue: Option[T] = lastValue
override def subscribe(subscriber: Subscriber): RxConnection = multicast.subscribe(subscriber)
}
class RxValue[T](initValue: T) extends BaseRxOut[T](Some(initValue)) {
def value: T = this.lastValue.get
def value_=(value: T): Unit = {
this.lastValue = Some(value)
}
}
trait InputConnector[T] {
def connectInput(input: RxOut[T]): RxConnection
}
class InputConnectorImpl[T] extends BaseRxOut[T](None) with InputConnector[T] {
val inputHolder = new RxValue[Option[(RxOut[T], RxConnection)]](None)
private def updateValue(): Unit = {
lastValue = for {inputWithDisconnect <- inputHolder.value
value <- inputWithDisconnect._1.currentValue}
yield value
}
override def connectInput(input: RxOut[T]): RxConnection = {
val current = inputHolder.value
if (current.exists(iwd => iwd._1 == input))
current.get._2
else {
current.foreach(iwd => iwd._2.disconnect())
inputHolder.value = Some(input, input.subscribe(() => this.updateValue()))
updateValue()
new RxConnection {
override def disconnect(): Unit = {
if (inputHolder.value.exists(iwd => iwd._1 == input)) {
inputHolder.value.foreach(iwd => iwd._2.disconnect())
inputHolder.value = None
updateValue()
}
}
}
}
}
}
abstract class BaseRxCalculation[Out] extends BaseRxOut[Out](None) {
protected def registerConnectors(connectors: InputConnectorImpl[_]*): Unit = {
connectors.foreach(c => c.subscribe(() => this.recalculate()))
}
private def recalculate(): Unit = {
var newValue = calculateOutput()
if (newValue != lastValue) {
lastValue = newValue
}
}
protected def calculateOutput(): Option[Out]
}
case class RxCalculation1[In1, Out](func: Function1[In1, Out]) extends BaseRxCalculation[Out] {
private val conn1Impl = new InputConnectorImpl[In1]
def conn1: InputConnector[In1] = conn1Impl // show to the outer world only InputConnector
registerConnectors(conn1Impl)
override protected def calculateOutput(): Option[Out] = {
for {v1 <- conn1Impl.currentValue}
yield func(v1)
}
}
case class RxCalculation2[In1, In2, Out](func: Function2[In1, In2, Out]) extends BaseRxCalculation[Out] {
private val conn1Impl = new InputConnectorImpl[In1]
def conn1: InputConnector[In1] = conn1Impl // show to the outer world only InputConnector
private val conn2Impl = new InputConnectorImpl[In2]
def conn2: InputConnector[In2] = conn2Impl // show to the outer world only InputConnector
registerConnectors(conn1Impl, conn2Impl)
override protected def calculateOutput(): Option[Out] = {
for {v1 <- conn1Impl.currentValue
v2 <- conn2Impl.currentValue}
yield func(v1, v2)
}
}
// add more RxCalculationN if needed
And you can use it like this:
def test(): Unit = {
val pipe2 = new RxCalculation1((in: Double) => {
println(s"in = $in")
val vel = 3.4
val V = 300
val a = 10.2
val TotV = V + in
TotV * a / vel
})
val in1 = new RxValue(2.0)
println(pipe2.currentValue)
val conn1 = pipe2.conn1.connectInput(in1)
println(pipe2.currentValue)
in1.value = 3.0
println(pipe2.currentValue)
conn1.disconnect()
println(pipe2.currentValue)
}
which prints
None
in = 2.0
Some(905.9999999999999)
in = 3.0
Some(909.0)
None
Here your "pipe" is RxCalculation1 (or other RxCalculationN) which wraps a function and you can "connect" and "disconnect" other "pipes" or just "values" to various inputs and start a chain of updates.

Make a lazy field be evaluated [duplicate]

Is it possible to do that in Scala using only val:
class MyClass {
private val myVal1: MyClass2 //.....????? what should be here?
def myMethod1(param1: Int) = {
myVal1 = new MyClass2(param1)
//....
// some code....
}
}
The idea is that I can't initialize myVal1 immediately since the argument for its constructor is unknown yet and I have to do that in myMethod1. myVal1 should be visible withing a class and should be immutable.
No mutable state allowed.
So is it possible?
No, it isn't possible to do in the way you want. Consider, what would be the result of
val mc = new MyClass
mc.method1(0)
mc.method1(1)
? An exception thrown for setting myVal1 twice? Or should it keep the first value?
This is not possible, but there are some ways (in addition to using param1 as a constructor parameter)
Change the var into an Option; the setter myMethod1 returns a new instance of the same class with the Option set to the value.
Create a separate mutable Builder class with a var, and turn it into an immutable one later, when all data has been collected
If you are dealing with forward or cyclic references, consider using call-by-name and lazy vals (example 1, example 2)
Update: Example for 1:
class MyClass(val myVal1: Option[Int]) {
def myMethod1(param1: Int): MyClass = {
new MyClass(Some(param1))
}
}
object MyClass {
def apply() = new MyClass(None)
def apply(i: Int) = new MyClass(Some(i))
}
This pattern is used by immutable.Queue for example.
Update: Example for 3 (cyclic reference):
// ref ... call by name
class MyClass(val id: Int, ref: => MyClass) {
lazy val myVal1 = ref
override def toString: String = s"$id -> ${myVal1.id}"
}
to be used like this:
val a: MyClass = new MyClass(1, b)
val b: MyClass = new MyClass(2, a)
println(a)
println(b)
Update: Example for 3 (forward reference):
class MyClass2(val id: Int)
// ref ... call by name
class MyClass(val id: Int, ref: => MyClass2) {
lazy val myVal1 = ref
override def toString: String = s"$id -> ${myVal1.id}"
}
to be used with
val a = new MyClass(1, x)
println(a.id) // You can use a.id, but not yet the lazy val
val x = new MyClass2(10)
println(a)
To imitate a lazy "value" whose initial value might not be retrieved until after instance initialization completes (btw, there is nothing special about such objects, e.g. Swift have lazy properties that are even recommended to be declared as variables), you can introduce a wrapper to repeat the same logic that the Scala compiler generates internally for lazy values in Scala:
class LazyVar[T] {
private[this] var value$compute: () => T = () => null.asInstanceOf[T]
#volatile private[this] var value$: T = null.asInstanceOf[T]
#volatile private[this] var isInitialized$ = false
#volatile private[this] var isComputed$ = false
def value_=(value: T) = this.synchronized {
if(!isInitialized$) {
value$compute = () => value
isInitialized$ = true
}
else throw new IllegalStateException("Already initialized")
}
def value: T = this.synchronized {
if(!isInitialized$) throw new IllegalStateException("Not yet initialized")
else if(isComputed$) value$
else {
value$ = value$compute()
isComputed$ = true
value$
}
}
}
Now you just have to change MyClass2 to LazyVar[MyClass2] keeping tha val keyword as you wanted:
case class MyClass2(param: Int)
class MyClass {
private val myVal1: LazyVar[MyClass2] = new LazyVar[MyClass2]
def this(param: Int) {
this()
println("Storing the result of an expensive function...")
myVal1.value = new MyClass2(param)
}
def debug() = println(myVal1.value)
}
Now, if you write something like
val myClass = new MyClass(42)
myClass.debug
myClass.debug
you'll see the value is only computed once:
Storing the result of an expensive function...
MyClass2(42)
MyClass2(42)

Initializing a val lately

Is it possible to do that in Scala using only val:
class MyClass {
private val myVal1: MyClass2 //.....????? what should be here?
def myMethod1(param1: Int) = {
myVal1 = new MyClass2(param1)
//....
// some code....
}
}
The idea is that I can't initialize myVal1 immediately since the argument for its constructor is unknown yet and I have to do that in myMethod1. myVal1 should be visible withing a class and should be immutable.
No mutable state allowed.
So is it possible?
No, it isn't possible to do in the way you want. Consider, what would be the result of
val mc = new MyClass
mc.method1(0)
mc.method1(1)
? An exception thrown for setting myVal1 twice? Or should it keep the first value?
This is not possible, but there are some ways (in addition to using param1 as a constructor parameter)
Change the var into an Option; the setter myMethod1 returns a new instance of the same class with the Option set to the value.
Create a separate mutable Builder class with a var, and turn it into an immutable one later, when all data has been collected
If you are dealing with forward or cyclic references, consider using call-by-name and lazy vals (example 1, example 2)
Update: Example for 1:
class MyClass(val myVal1: Option[Int]) {
def myMethod1(param1: Int): MyClass = {
new MyClass(Some(param1))
}
}
object MyClass {
def apply() = new MyClass(None)
def apply(i: Int) = new MyClass(Some(i))
}
This pattern is used by immutable.Queue for example.
Update: Example for 3 (cyclic reference):
// ref ... call by name
class MyClass(val id: Int, ref: => MyClass) {
lazy val myVal1 = ref
override def toString: String = s"$id -> ${myVal1.id}"
}
to be used like this:
val a: MyClass = new MyClass(1, b)
val b: MyClass = new MyClass(2, a)
println(a)
println(b)
Update: Example for 3 (forward reference):
class MyClass2(val id: Int)
// ref ... call by name
class MyClass(val id: Int, ref: => MyClass2) {
lazy val myVal1 = ref
override def toString: String = s"$id -> ${myVal1.id}"
}
to be used with
val a = new MyClass(1, x)
println(a.id) // You can use a.id, but not yet the lazy val
val x = new MyClass2(10)
println(a)
To imitate a lazy "value" whose initial value might not be retrieved until after instance initialization completes (btw, there is nothing special about such objects, e.g. Swift have lazy properties that are even recommended to be declared as variables), you can introduce a wrapper to repeat the same logic that the Scala compiler generates internally for lazy values in Scala:
class LazyVar[T] {
private[this] var value$compute: () => T = () => null.asInstanceOf[T]
#volatile private[this] var value$: T = null.asInstanceOf[T]
#volatile private[this] var isInitialized$ = false
#volatile private[this] var isComputed$ = false
def value_=(value: T) = this.synchronized {
if(!isInitialized$) {
value$compute = () => value
isInitialized$ = true
}
else throw new IllegalStateException("Already initialized")
}
def value: T = this.synchronized {
if(!isInitialized$) throw new IllegalStateException("Not yet initialized")
else if(isComputed$) value$
else {
value$ = value$compute()
isComputed$ = true
value$
}
}
}
Now you just have to change MyClass2 to LazyVar[MyClass2] keeping tha val keyword as you wanted:
case class MyClass2(param: Int)
class MyClass {
private val myVal1: LazyVar[MyClass2] = new LazyVar[MyClass2]
def this(param: Int) {
this()
println("Storing the result of an expensive function...")
myVal1.value = new MyClass2(param)
}
def debug() = println(myVal1.value)
}
Now, if you write something like
val myClass = new MyClass(42)
myClass.debug
myClass.debug
you'll see the value is only computed once:
Storing the result of an expensive function...
MyClass2(42)
MyClass2(42)

Call to == does not opt to equals

I have the following class:
abstract class IRDMessage extends Ordered[IRDMessage] {
val messageType: MessageType.Type
val timestamp: DateTime
val content: AnyRef
def compare(that: IRDMessage): Int = {
val res = timestamp compareTo that.timestamp
res
}
override def equals(obj: Any): Boolean = obj match{
case message: IRDMessage => compareTo(message) == 0
case _ => false
}
}
I have a couple of concrete implementations as well. However, when I try to say a == b of any subtype of IRDMessage the equals method does not get called and it simply compares references (default equals implementation). Any ideas what might be causing this?
The subclasses are simple case classes btw.
This does actually work given the following simplified example:
object MessageTest {
def main(args: Array[String]) {
val m1 = MessageImpl("foo")
val m2 = MessageImpl("bar")
m1 == m2
}
}
abstract class IRDMessage extends Ordered[IRDMessage] {
val content: AnyRef
override def equals(obj: Any): Boolean = {
println("in here")
obj match{
case message: IRDMessage => compareTo(message) == 0
case _ => false
}
}
}
case class MessageImpl(content:String) extends IRDMessage{
override def compare(that:IRDMessage) = 0
}
Can you post a little more code, specifically one of your sample case classes? I noticed if I defined the case class like so:
case class MessageImpl extends IRDMessage{
var content = "foo"
override def compare(that:IRDMessage) = 0
}
It does not work as expected.