309

How do I break out a loop?

var largest=0
for(i<-999 to 1 by -1) {
    for (j<-i to 1 by -1) {
        val product=i*j
        if (largest>product)
            // I want to break out here
        else
           if(product.toString.equals(product.toString.reverse))
              largest=largest max product
    }
}

How do I turn nested for loops into tail recursion?

From Scala Talk at FOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261 on the 22nd page:

Break and continue Scala does not have them. Why? They are a bit imperative; better use many smaller functions Issue how to interact with closures. They are not needed!

What is the explanation?

bjb568
  • 11,089
  • 11
  • 50
  • 71
TiansHUo
  • 8,509
  • 7
  • 45
  • 57
  • Your comparision needs a second equals-sign: if(product.toString == product.toString.reverse) or maybe an equals-Method-call. – user unknown Apr 30 '10 at 10:04
  • yeah, i missed that one when i was typing it in – TiansHUo May 04 '10 at 04:13
  • I know I'm resurrecting an old question but I would love to know what the purpose of this code is? I first though that you were trying to find the largest "palindrome" product possible with the given combinations of `i` and `j`. If this code runs to completion without breaking out of the loop, the result is `906609` but by breaking out of the loop early, the result is `90909` so breaking out of the loop is not making the code "more efficient" as it is altering the result. – Ryan H. Jul 20 '18 at 00:54

19 Answers19

402

You have three (or so) options to break out of loops.

Suppose you want to sum numbers until the total is greater than 1000. You try

var sum = 0
for (i <- 0 to 1000) sum += i

except you want to stop when (sum > 1000).

What to do? There are several options.

(1a) Use some construct that includes a conditional that you test.

var sum = 0
(0 to 1000).iterator.takeWhile(_ => sum < 1000).foreach(i => sum+=i)

(warning--this depends on details of how the takeWhile test and the foreach are interleaved during evaluation, and probably shouldn't be used in practice!).

(1b) Use tail recursion instead of a for loop, taking advantage of how easy it is to write a new method in Scala:

var sum = 0
def addTo(i: Int, max: Int) {
  sum += i; if (sum < max) addTo(i+1,max)
}
addTo(0,1000)

(1c) Fall back to using a while loop

var sum = 0
var i = 0
while (i <= 1000 && sum <= 1000) { sum += i; i += 1 }

(2) Throw an exception.

object AllDone extends Exception { }
var sum = 0
try {
  for (i <- 0 to 1000) { sum += i; if (sum>=1000) throw AllDone }
} catch {
  case AllDone =>
}

(2a) In Scala 2.8+ this is already pre-packaged in scala.util.control.Breaks using syntax that looks a lot like your familiar old break from C/Java:

import scala.util.control.Breaks._
var sum = 0
breakable { for (i <- 0 to 1000) {
  sum += i
  if (sum >= 1000) break
} }

(3) Put the code into a method and use return.

var sum = 0
def findSum { for (i <- 0 to 1000) { sum += i; if (sum>=1000) return } }
findSum

This is intentionally made not-too-easy for at least three reasons I can think of. First, in large code blocks, it's easy to overlook "continue" and "break" statements, or to think you're breaking out of more or less than you really are, or to need to break two loops which you can't do easily anyway--so the standard usage, while handy, has its problems, and thus you should try to structure your code a different way. Second, Scala has all sorts of nestings that you probably don't even notice, so if you could break out of things, you'd probably be surprised by where the code flow ended up (especially with closures). Third, most of Scala's "loops" aren't actually normal loops--they're method calls that have their own loop, or they are recursion which may or may not actually be a loop--and although they act looplike, it's hard to come up with a consistent way to know what "break" and the like should do. So, to be consistent, the wiser thing to do is not to have a "break" at all.

Note: There are functional equivalents of all of these where you return the value of sum rather than mutate it in place. These are more idiomatic Scala. However, the logic remains the same. (return becomes return x, etc.).

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
  • There's one more. Make it a method, and `return` explicitly. – Daniel C. Sobral Apr 30 '10 at 23:31
  • @Daniel: Um, doesn't (3) cover that? – Rex Kerr May 01 '10 at 00:05
  • I was thinking of `return sum`, not just `return`, but I guess it does. – Daniel C. Sobral May 01 '10 at 11:39
  • @rex kerr, 1a is slow, because memory for the stream is initialized, especially if this is in an inner loop 1b is what i was thinking of, but i see that i will need two tail recursions, and that's not good for clarity at all 2 and 3 are slower than direct loops – TiansHUo May 04 '10 at 04:11
  • 3
    You can use `.iterator` (`.elements` in 2.7) instead of `.toStream` to avoid saving things in memory. I was giving examples of each, not necessarily specifying the fastest for your exact case. What are your benchmarks for (2) and (3)? How much slower are they? – Rex Kerr May 04 '10 at 15:06
  • To be frank, I didn't do any benchmarks. But I would like to point out, any overhead in an inner loop should be eliminated – TiansHUo May 06 '10 at 08:19
  • @TiansHUo: Indeed it should. Do you realize how much overhead there is if you write `for (i <- 1 to 1000000) { ... }` instead of using a while loop? And a while loop is a special case of (1a)--just check some other condition to break early. – Rex Kerr May 06 '10 at 10:16
  • @Rex Kerr, actually I don't, why the overhead for a for-loop? – TiansHUo May 07 '10 at 10:05
  • 1
    @TiansHUo: Because `for` is translated into a `foreach` call (possibly with other calls along the way), and that's all entirely generic, which is not as fast as incrementing a primitive counter. If you really want code to be fast, use `var i=0; while (i<1000) { i+=1; ... }`. Except in inner loops, though, there's no particular reason to be fast, so it's better to use the more powerful / flexible / convenient approach. – Rex Kerr May 07 '10 at 14:10
  • @kerr, what?! How did you know this? – TiansHUo May 09 '10 at 12:32
  • 1
    @TiansHUo: I read Programming In Scala by Odersky et al, where the for loop is described, and I benchmarked various loops to see how they performed. – Rex Kerr May 09 '10 at 16:16
  • This is somewhat related to this question: http://stackoverflow.com/questions/3770989/purpose-of-return-statement-in-scala . – Jus12 Feb 28 '11 at 06:45
  • 9
    Re exceptions, although strictly true that you can throw an exception, this is arguably an abuse of the exception mechanism (see Effective Java). Exceptions are really to indicate situations that are truly unexpected and/or require a drastic escape from the code, i.e. errors of some kind. Quite apart from that, they certainly used to be pretty slow (not sure about the current situation) because there's little reason for JVMs to optimize them. – Jonathan May 30 '11 at 00:24
  • 28
    @Jonathan - Exceptions are only slow if you need to compute a stack trace--notice how I created a static exception to throw instead of generating one on the fly! And they're a perfectly valid control construct; they're used in multiple places throughout the Scala library, since they're really the only way you can return through multiple methods (which if you have a pile of closures is something you sometimes need to do). – Rex Kerr May 30 '11 at 01:22
  • For me the best solution is tail recursion, so neat! – Galder Zamarreño Aug 03 '11 at 17:12
  • 1
    In the recursive `addTo` method it seems cleaner to put `sum` as a parameter and have the method return an Int rather than Unit, so you don't have to use mutable `var`s. Number (4) for the list could be to replace the for-comprehensions with equivalent while-loops with appropriate stopping conditions. – Luigi Plinge Aug 19 '11 at 23:14
  • 2
    @macias - Use `breakable`, then. – Rex Kerr Jan 19 '12 at 20:42
  • @Rex Kerr, no-go, if I am not mistaken it is based on exceptions. I think on-fly inner function is better approach. – greenoldman Jan 20 '12 at 07:06
  • @macias - What is wrong with using exceptions as part of your control flow mechanism? Each mechanism has its own strengths and weaknesses. – Rex Kerr Jan 20 '12 at 17:31
  • 18
    @Rex Kerr, you are pointing out weaknesses of the break construct (I don't agree with them), but then you suggest using **exceptions** for normal workflow! Exiting a loop is not an exceptional case, it is part of the algorithm, it is not the case of writing to non-existing file (for example). So in short suggested "cure" is worse than the "illness" itself. And when I consider throwing a real exception in `breakable` section... and all those hoops just to avoid evil `break`, hmm ;-) You have to admit, life is ironic. – greenoldman Jan 23 '12 at 17:40
  • 18
    @macias - Sorry, my mistake. The JVM is using Throwables for control flow. Better? Just because they're typically used to support exception handling does not mean they can only be used for exception handling. Returning to a defined location from within a closure is _just like_ throwing an exception in terms of control flow. No surprise, then, that this is the mechanism that is used. – Rex Kerr Jan 23 '12 at 21:40
  • @Rex Kerr, I'll stop here because it is more and more like a personal chat (now I would have to question if Java and JVM is something with proven design quality). I am not convinced at all, but until we find a better place to discuss this, let's stop OK? – greenoldman Jan 24 '12 at 13:08
  • 15
    @RexKerr Well, for what it's worth you convinced me. Normally I'd be one to rail against Exceptions for normal program flow, but the two main reasons don't apply here. Those are: (1) they're slow [not when used in this way], and (2) they suggest exceptional behavior to someone reading your code [not if your library lets you call them `break`] If it look's like a `break` and it performs like a `break`, as far as I'm concerned it's a `break`. – Tim Goodman Jan 24 '14 at 19:32
  • 3
    Do I understand correctly that `return` inside a `for` body is compiled to `throw new SomeException` and `for` construct is put inside a try-catch? Because I don't see another way how could this be implemented. – sasha.sochka Apr 13 '14 at 17:54
  • 1
    I've found the answer myself - my understanding was correct. In place of `return` this exception is thrown: `scala.runtime.NonLocalReturnControl` – sasha.sochka Apr 13 '14 at 18:07
  • 2
    Of these options, only 1a and 1b are substantially different to 'break'. Example 2 uses an exception in exactly the same way as 'break' would be used, only with additional boilerplate to define the exception class. Example 3 uses 'return' in exactly the same way that 'break' would be used, only with additional boilerplate to define a closure. If it's easy to overlook 'break' or 'continue' in the middle of a loop, how come the words 'return' and 'throw' are somehow magically different? – Josh Milthorpe Apr 06 '15 at 11:23
  • I think for procedure programming, use while loop is better – Cyanny Nov 09 '16 at 05:45
  • 1
    (1c) has a typo: should be `sum += i`, not `sum += 1` – Smylic Apr 28 '23 at 15:54
77

This has changed in Scala 2.8 which has a mechanism for using breaks. You can now do the following:

import scala.util.control.Breaks._
var largest = 0
// pass a function to the breakable method
breakable { 
    for (i<-999 to 1  by -1; j <- i to 1 by -1) {
        val product = i * j
        if (largest > product) {
            break  // BREAK!!
        }
        else if (product.toString.equals(product.toString.reverse)) {
            largest = largest max product
        }
    }
}
hohonuuli
  • 1,974
  • 15
  • 15
  • 3
    Does this use exceptions under the hood? – Mike May 31 '11 at 18:23
  • This is using Scala as a procedural language ignoring the functional programming advantages (i.e. tail recursion). Not pretty. – Galder Zamarreño Aug 03 '11 at 17:13
  • 32
    Mike: Yes, Scala is throwing an exception to break out of the loop. Galder: This answers the posted question "How do I break out of a loop in Scala?". Whether it's 'pretty' or not isn't relevant. – hohonuuli Oct 07 '11 at 00:18
  • 2
    @hohonuuli, so it is in try-catch block it won't break, right? – greenoldman Jan 19 '12 at 20:13
  • @macias, that's right. If you surround the 'break' statement with a try/catch it won't break out of the loop. (I did test that). For the curious, the source code for Breaks is at http://www.scala-lang.org/api/current/index.html#scala.util.control.Breaks – hohonuuli Jan 20 '12 at 17:12
  • You can put that in the categories of "leaky abstractions". A bit sad, but that's the price to pay for running on a VM that was not written to support scala's constructs Then again, you're not supposed to catch all throwables. The recommended way to write a proper "catch all" handler is to use `NonFatal`, which not coincidently will not catch `NonLocalReturnControl` (the exception used internally when doing a `return` from inside an anonymous function) nor `BreakControl` (the one used to implement the `break` construct) – Régis Jean-Gilles Jun 08 '15 at 13:18
  • 2
    @Galder Zamarreño Why is tail recursion an advantage in this case? Isn't it simply an optimization (who's application is hidden for the newcomer and confusingly applied for the experienced). Is there any benefit for tail recursion in this example? – user48956 Apr 26 '16 at 16:06
47

It is never a good idea to break out of a for-loop. If you are using a for-loop it means that you know how many times you want to iterate. Use a while-loop with 2 conditions.

for example

var done = false
while (i <= length && !done) {
  if (sum > 1000) {
     done = true
  }
}
Community
  • 1
  • 1
Keith Blanchard
  • 603
  • 5
  • 3
  • 3
    This is what I feel is the right way to break out of loops in Scala. Is there anything wrong with this answer? (considering the low number of upvotes). – Jus12 Sep 18 '15 at 06:37
  • 1
    indeed simple and more readable. even the breakable -- break thingy is correct, it looks ugly and has problems with in inner try-catch. Although your solution doesn't work with a foreach, I will vote you up, honoring the simplicity. – yerlilbilgin Feb 25 '16 at 14:44
16

To add Rex Kerr answer another way:

  • (1c) You can also use a guard in your loop:

     var sum = 0
     for (i <- 0 to 1000 ; if sum<1000) sum += i
    
Patrick
  • 15,702
  • 1
  • 39
  • 39
  • 32
    I didn't include this as an option because it doesn't actually break the loop--it runs through all of it, but the if statement fails on every iteration after the sum is high enough, so it only does one if-statement's worth of work each time. Unfortunately, depending on how you've written the loop, that could be a lot of work. – Rex Kerr Apr 30 '10 at 13:30
  • @RexKerr: Wouldn't the compiler optimize it out anyway? Won't it be optimized out if not during first run then during JIT. – Maciej Piechotka Jan 01 '12 at 02:46
  • 5
    @MaciejPiechotka - The JIT compiler generally doesn't contain sufficiently sophisticated logic to recognize that an if-statement on a changing variable will always (in this particular special situation) return false and thus can be omitted. – Rex Kerr Jan 01 '12 at 06:13
8

Simply We can do in scala is

scala> import util.control.Breaks._

scala> object TestBreak {
       def main(args : Array[String]) {
         breakable {
           for (i <- 1 to 10) {
             println(i)
             if (i == 5)
               break;
       } } } }

output :

scala> TestBreak.main(Array())
1
2
3
4
5
wwkudu
  • 2,778
  • 3
  • 28
  • 41
Viraj Wadate
  • 5,447
  • 1
  • 31
  • 29
  • ``` warning: Auto-application to `()` is deprecated. Supply the empty argument list `()` explicitly to invoke method break, or remove the empty argument list from its definition (Java-defined methods are exempt). In Scala 3, an unapplied method like this will be eta-expanded into a function. ``` – RixTheTyrunt Jun 21 '22 at 15:39
7

Since there is no break in Scala yet, you could try to solve this problem with using a return-statement. Therefore you need to put your inner loop into a function, otherwise the return would skip the whole loop.

Scala 2.8 however includes a way to break

http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html

emtrane
  • 1,049
  • 1
  • 8
  • 10
Ham Vocke
  • 2,942
  • 22
  • 27
  • sorry, but I only wanted to break out the inner loop. You aren't implying that I should put it in a function? – TiansHUo Apr 30 '10 at 06:37
  • Sorry, should have clarified that. Sure using a return means that you need to encapsulate the loop in a function. I've edited my answer. – Ham Vocke Apr 30 '10 at 06:39
  • 1
    That's not nice at all. It seems that Scala doesn't like nested loops. – TiansHUo Apr 30 '10 at 06:46
  • There doesn't seem to be a different way. You might want to take a look at this: http://www.scala-lang.org/node/257 – Ham Vocke Apr 30 '10 at 06:56
  • 4
    @TiansHUo: Why do you say that Scala doesn't like _nested_ loops? You have the same issues if you are trying to break out of a _single_ loop. – Rex Kerr Apr 30 '10 at 07:37
7

An approach that generates the values over a range as we iterate, up to a breaking condition, instead of generating first a whole range and then iterating over it, using Iterator, (inspired in @RexKerr use of Stream)

var sum = 0
for ( i <- Iterator.from(1).takeWhile( _ => sum < 1000) ) sum += i
elm
  • 20,117
  • 14
  • 67
  • 113
5
// import following package
import scala.util.control._

// create a Breaks object as follows
val loop = new Breaks;

// Keep the loop inside breakable as follows
loop.breakable{
// Loop will go here
for(...){
   ....
   // Break will go here
   loop.break;
   }
}

use Break module http://www.tutorialspoint.com/scala/scala_break_statement.htm

user1836270
  • 71
  • 1
  • 2
5

Just use a while loop:

var (i, sum) = (0, 0)
while (sum < 1000) {
  sum += i
  i += 1
}
pathikrit
  • 32,469
  • 37
  • 142
  • 221
4

Here is a tail recursive version. Compared to the for-comprehensions it is a bit cryptic, admittedly, but I'd say its functional :)

def run(start:Int) = {
  @tailrec
  def tr(i:Int, largest:Int):Int = tr1(i, i, largest) match {
    case x if i > 1 => tr(i-1, x)
    case _ => largest
  }

  @tailrec
  def tr1(i:Int,j:Int, largest:Int):Int = i*j match {
    case x if x < largest || j < 2 => largest
    case x if x.toString.equals(x.toString.reverse) => tr1(i, j-1, x)
    case _ => tr1(i, j-1, largest)
  }

  tr(start, 0)
}

As you can see, the tr function is the counterpart of the outer for-comprehensions, and tr1 of the inner one. You're welcome if you know a way to optimize my version.

fresskoma
  • 25,481
  • 10
  • 85
  • 128
2

Close to your solution would be this:

var largest = 0
for (i <- 999 to 1 by -1;
  j <- i to 1 by -1;
  product = i * j;
  if (largest <= product && product.toString.reverse.equals (product.toString.reverse.reverse)))
    largest = product

println (largest)

The j-iteration is made without a new scope, and the product-generation as well as the condition are done in the for-statement (not a good expression - I don't find a better one). The condition is reversed which is pretty fast for that problem size - maybe you gain something with a break for larger loops.

String.reverse implicitly converts to RichString, which is why I do 2 extra reverses. :) A more mathematical approach might be more elegant.

user unknown
  • 35,537
  • 11
  • 75
  • 121
2

I am new to Scala, but how about this to avoid throwing exceptions and repeating methods:

object awhile {
def apply(condition: () => Boolean, action: () => breakwhen): Unit = {
    while (condition()) {
        action() match {
            case breakwhen(true)    => return ;
            case _                  => { };
        }
    }
}
case class breakwhen(break:Boolean);

use it like this:

var i = 0
awhile(() => i < 20, () => {
    i = i + 1
    breakwhen(i == 5)
});
println(i)

if you don’t want to break:

awhile(() => i < 20, () => {
    i = i + 1
    breakwhen(false)
});
2

The third-party breakable package is one possible alternative

https://github.com/erikerlandson/breakable

Example code:

scala> import com.manyangled.breakable._
import com.manyangled.breakable._

scala> val bkb2 = for {
     |   (x, xLab) <- Stream.from(0).breakable   // create breakable sequence with a method
     |   (y, yLab) <- breakable(Stream.from(0))  // create with a function
     |   if (x % 2 == 1) continue(xLab)          // continue to next in outer "x" loop
     |   if (y % 2 == 0) continue(yLab)          // continue to next in inner "y" loop
     |   if (x > 10) break(xLab)                 // break the outer "x" loop
     |   if (y > x) break(yLab)                  // break the inner "y" loop
     | } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2

scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))
eje
  • 945
  • 11
  • 22
  • ``` error: object manyangled is not a member of package com import com.manyangled.breakable._ ^ main.scala:35: error: not found: value break ``` – RixTheTyrunt Jun 21 '22 at 15:41
2
import scala.util.control._

object demo_brk_963 
{
   def main(args: Array[String]) 
   {
      var a = 0;
      var b = 0;
      val numList1 = List(1,2,3,4,5,6,7,8,9,10);
      val numList2 = List(11,12,13);

      val outer = new Breaks; //object for break
      val inner = new Breaks; //object for break

      outer.breakable // Outer Block
      {
         for( a <- numList1)
         {
            println( "Value of a: " + a);

            inner.breakable // Inner Block
            {
               for( b <- numList2)
               {
                  println( "Value of b: " + b);

                  if( b == 12 )
                  {
                      println( "break-INNER;");
                       inner.break;
                  }
               }
            } // inner breakable
            if( a == 6 )
            {
                println( "break-OUTER;");
                outer.break;
            }
         }
      } // outer breakable.
   }
}

Basic method to break the loop, using Breaks class. By declaring the loop as breakable.

1

Ironically the Scala break in scala.util.control.Breaks is an exception:

def break(): Nothing = { throw breakException }

The best advice is: DO NOT use break, continue and goto! IMO they are the same, bad practice and an evil source of all kind of problems (and hot discussions) and finally "considered be harmful". Code block structured, also in this example breaks are superfluous. Our Edsger W. Dijkstra† wrote:

The quality of programmers is a decreasing function of the density of go to statements in the programs they produce.

Epicurist
  • 903
  • 11
  • 17
1

I got a situation like the code below

 for(id<-0 to 99) {
    try {
      var symbol = ctx.read("$.stocks[" + id + "].symbol").toString
      var name = ctx.read("$.stocks[" + id + "].name").toString
      stocklist(symbol) = name
    }catch {
      case ex: com.jayway.jsonpath.PathNotFoundException=>{break}
    }
  }

I am using a java lib and the mechanism is that ctx.read throw a Exception when it can find nothing. I was trapped in the situation that :I have to break the loop when a Exception was thrown, but scala.util.control.Breaks.break using Exception to break the loop ,and it was in the catch block thus it was caught.

I got ugly way to solve this: do the loop for the first time and get the count of the real length. and use it for the second loop.

take out break from Scala is not that good,when you are using some java libs.

Lucas Liu
  • 823
  • 1
  • 10
  • 12
1

Clever use of find method for collection will do the trick for you.

var largest = 0
lazy val ij =
  for (i <- 999 to 1 by -1; j <- i to 1 by -1) yield (i, j)

val largest_ij = ij.find { case(i,j) =>
  val product = i * j
  if (product.toString == product.toString.reverse)
    largest = largest max product
  largest > product
}

println(largest_ij.get)
println(largest)
AlvaPan
  • 519
  • 3
  • 12
1

Below is code to break a loop in a simple way

import scala.util.control.Breaks.break

object RecurringCharacter {
  def main(args: Array[String]) {
    val str = "nileshshinde";

    for (i <- 0 to str.length() - 1) {
      for (j <- i + 1 to str.length() - 1) {

        if (str(i) == str(j)) {
          println("First Repeted Character " + str(i))
          break()     //break method will exit the loop with an Exception "Exception in thread "main" scala.util.control.BreakControl"

        }
      }
    }
  }
}
Nilesh Shinde
  • 457
  • 5
  • 10
1

I don't know how much Scala style has changed in the past 9 years, but I found it interesting that most of the existing answers use vars, or hard to read recursion. The key to exiting early is to use a lazy collection to generate your possible candidates, then check for the condition separately. To generate the products:

val products = for {
  i <- (999 to 1 by -1).view
  j <- (i to 1 by -1).view
} yield (i*j)

Then to find the first palindrome from that view without generating every combination:

val palindromes = products filter {p => p.toString == p.toString.reverse}
palindromes.head

To find the largest palindrome (although the laziness doesn't buy you much because you have to check the entire list anyway):

palindromes.max

Your original code is actually checking for the first palindrome that is larger than a subsequent product, which is the same as checking for the first palindrome except in a weird boundary condition which I don't think you intended. The products are not strictly monotonically decreasing. For example, 998*998 is greater than 999*997, but appears much later in the loops.

Anyway, the advantage of the separated lazy generation and condition check is you write it pretty much like it is using the entire list, but it only generates as much as you need. You sort of get the best of both worlds.

Karl Bielefeldt
  • 47,314
  • 10
  • 60
  • 94