This is not necessarily a Scala issue, it is a design issue that is related to the prevention of a volatile state, functional thinking and such. It just happens that I use Scala.
Given this set of requirements:
The input comes from an essentially infinite stream of random numbers between 1 and 10
End result: SUCCEED or FAIL
At any given time, there can be several listening to several objects, and they can start listening at different times, so that they all can have a different concept of the “first” number; therefore, stream listeners should be separate from the stream itself.
pseudo code:
if (first number == 1) SUCCEED else if (first number >= 9) FAIL else { first = first number rest = rest of stream for each (n in rest) { if (n == 1) FAIL else if (n == first) SUCCEED else continue } }
Here is a possible mutable implementation:
sealed trait Result case object Fail extends Result case object Succeed extends Result case object NoResult extends Result class StreamListener { private var target: Option[Int] = None def evaluate(n: Int): Result = target match { case None => if (n == 1) Succeed else if (n >= 9) Fail else { target = Some(n) NoResult } case Some(t) => if (n == t) Succeed else if (n == 1) Fail else NoResult } }
It will work, but it smells to me. StreamListener.evaluate is not link transparent. And using the NoResult token just doesn't seem right. This has the advantage, although clear and user-friendly / code. Also, should there be a functional solution to this right?
I came up with two more options:
Evaluating return a (possibly new) StreamListener, but that means I will need to make Result a subtype of StreamListener, which doesn't feel good.
When evaluating, we will take Stream [Int] as a parameter and let StreamListener be responsible for consuming as much of the stream as possible, as it is necessary to determine failure or success. The problem that I see with this approach is that the class that registers the listeners must request each listener after creating each number and take the appropriate action immediately after a failure or success. With this approach, I don’t see how this can happen, as each listener forces Stream to evaluate until it completes the evaluation. There is no concept of generating a single number.
Is there any standard Scala / FP idiom I am looking at here?
source share