Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

conditional loop conversion in Scala

Tags:

for-loop

scala

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))

like image 381
oxbow_lakes Avatar asked Dec 13 '22 02:12

oxbow_lakes


1 Answers

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
}
like image 129
Mitch Blevins Avatar answered Jan 09 '23 10:01

Mitch Blevins