23

Scala does not have break or continue, so some loop behavior takes a bit more of thinking.

Ending a loop early requires tail recursion, exceptions, or scala.util.control.Breaks (which uses exceptions).

The rationale for this is that, like goto, they are flow constructs that obscure flow, and can be accomplished in better, less surprising ways.

But it seems those same arguments could be used for return.

Why did Scala deliberately omit break and continue, but not return?

Paul Draper
  • 5,972
  • 3
  • 22
  • 37
  • 1
    I can imagine that the authors of the language consider tail recursion as _the_ way to construct iteration. I can imagine that `break` and `continue` need some additional cleanup machinery. OTOH `return` is a way to orderly terminate a function, and any cleanup machinery is already there anyway. – 9000 Oct 13 '14 at 15:14
  • 1
    There is `breakable { for { break; } }` but an afterthought, and likely far from efficient. – Joop Eggen Oct 13 '14 at 15:17
  • Because with functions there is actually no reason for it. It's the same in python. Each time you use a for-loop with break, you can instead write a function, put your loop into the function and use return. I cannot think of a situation where this is not a good idea regarding clean-code. For performance, a clean might be better, but performance does not have highest priority in scala. – valenterry Oct 13 '14 at 15:21
  • @PaulDraper just wanted to give concrete syntax, for newbies in Scala. – Joop Eggen Oct 13 '14 at 16:43
  • 2
    This question looks like it has an answer here: http://stackoverflow.com/questions/3770989/purpose-of-return-statement-in-scala?lq=1 – Michael Shaw Oct 13 '14 at 16:50
  • @MichaelShaw, an answer could have answered it, though none do, since there's no mention of `break` or `continue` and how `return` differs from these (if at all). – Paul Draper Oct 13 '14 at 21:55
  • 3
    @PaulDraper: The answer for `break` and `continue` is contained in your question and in the link in your question. The question for `return` is exactly what the question I linked was about, and was answered, at least in the top-voted, accepted answer. If the two answers put together don't answer your question, maybe you could edit the question to clarify it. – Michael Shaw Oct 13 '14 at 22:36
  • @MichaelShaw, in either SO post, I don't see anything that differs between break/continue and return. It seems as if everything applies the same to both. – Paul Draper Oct 14 '14 at 01:53

2 Answers2

17

Break and Continue:

In a talk about Scala, Martin Odersky gave 3 reasons not to include break or continue on slide 22:

  • They are a bit imperative; better use many smaller functions.
  • Issues how to interact with closures.
  • They are not needed!

And he then says, "We can support them purely in the libraries." On slide 23, he gives code that implements break. Although I don't quite know Scala well enough to be certain, it looks like the short snippet on that slide is all that's needed to implement break, and that continue could be implemented in code that is similarly short.

Being able to implement stuff like this in libraries simplifies the core language.

In 'Programming in Scala, Second Edition', by Martin Odersky, Lex Spoon, and Bill Venners, the following explanation is given:

You may have noticed that there has been no mention of break or continue. Scala leaves out these commands because they do not mesh well with function literals... It is clear what continue means inside a while loop, but what would it mean inside a function literal? ... There are many ways to program without break and continue, and if you take advantage of function literals, those alternatives can often be shorter than the original code.

Return:

Returns could be considered a bit imperative in style, since return is a verb, a command to do something. But they can also be seen in a purely functional/declarative way: they define what the return value of the function is (even if, in a function with multiple returns, they only each give a partial definition).

In the same book, they say the following about return:

In the absence of any explicit return statement, a Scala method returns the last value computed by the method. The recommended style for methods is in fact to avoid having explicit, and especially multiple, return statements. Instead, think of each method as an expression that yields one value, which is returned.

Methods end and return a value, even if a return statement isn't used, so there can be no issues with closures, since otherwise closures wouldn't work period.

There can also be no problem meshing well with function literals, since the function has to return a value anyway.

Michael Shaw
  • 5,116
  • 1
  • 21
  • 27
  • 2
    Regarding return, there do seem to be some mild dangers: http://tpolecat.github.io/2014/05/09/return.html – bbarker Sep 24 '16 at 19:31
0

I think the previous answers do justice to the problems of defining semantics for break or continue in a language-wide manner for Scala, with relatively unconstrained contexts.

I wrote a small library that defines break and continue in a more constrained context: iteration over sequences via Scala for-comprehensions. By focusing on that context, I believe that the semantics become unambiguous and easy to reason about.

The library is available here: https://github.com/erikerlandson/breakable

Here is a simple example of what it looks like in 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
  • 101
  • 1