I'd like to convert a piece of Java code which looks like the following into Scala:
for (Iterator<Task> it = tasks.iterator(); it.hasNext() && workflow.isAutoRun();) {
Task task = it.next();
if (!runTask(task)) break;
}
I am not a fan of the scala for-
comprehensions (not that I know how to break the iteration anyway) and I've come up with the following:
val completed = tasks.forall { task => workflow.isAutoRun && runTask(task) }
However, the scaladoc for the forall
method looks like the following (italics mine):
Apply a predicate
p
to all elements of this iterable object and return true, iff the predicate yields true for all elements
This is not equivalent to what I have done (because it implies that the predicate will be evaluated for each item, regardless of whether a previous evaluation has returned false
) and (in fact) not actually equivalent to what the forall
method actually does, which on Iterator
looks like:
def forall(p: A => Boolean): Boolean = {
var res = true
while (res && hasNext) res = p(next)
res
}
Anyway, I digress: has anyone got any better suggestions for what the scala code should look like? I want to see something which conveys the intent better:
tasks.doUntil(t => !isAutoRun || !runTask(t))
Similarly to Flaviu's answer above, you can put an implicit definition in scope somewhere:
implicit def conditionalLoop[T](s: Seq[T]) = {
new {
def doWhile(p: T => Boolean): Unit = {
doWhile(s.elements)(p)
}
private def doWhile(it: Iterator[T])(p: T => Boolean): Unit = {
if (it.hasNext && p(it.next)) doWhile(it)(p)
}
}
}
Then, calling is convenient:
tasks doWhile {
t => workflow.isAutoRun && t.run
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With