Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I break out of a loop in Scala?

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?

like image 816
TiansHUo Avatar asked Apr 30 '10 06:04

TiansHUo


People also ask

How do I completely break out of a for loop?

To break out of a for loop, you can use the endloop, continue, resume, or return statement. endfor; If condition is true, statementlist2 is not executed in that pass through the loop, and the entire loop is closed.

What is breakable in Scala?

Break is used to break a loop or program execution. It skips the current execution. Inside inner loop it breaks the execution of inner loop.

Is there a continue in Scala?

It's true that Scala doesn't have break and continue keywords, but it does offer similar functionality through scala. util. control. Breaks.


2 Answers

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 += 1; 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.).

like image 187
Rex Kerr Avatar answered Oct 13 '22 00:10

Rex Kerr


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         }     } } 
like image 31
hohonuuli Avatar answered Oct 12 '22 22:10

hohonuuli