In Progress
Unit 1, Lesson 21
In Progress

Break

Video transcript & code

Today I want to talk about the break keyword.

You've probably used the break keyword in your code. And you might think there's not much to say about it. It breaks out of loops, right? Whoop de do.

For instance, here's an infinite loop, which is rendered not-so-infinite by a break statement after the third iteration.

i = 0
while true
  puts "Iteration #{i}"
  break if i >= 2
  i += 1
end
# >> Iteration 0
# >> Iteration 1
# >> Iteration 2

What more can we say about break? As it turns out, quite a bit. But first, let's do away with the notion that break is all about loops. While it's true that in many other languages break is a loop control statement, in Ruby it represents a much more generalized concept. To illustrate this, let's bring back a method we've used in several other episodes. This method yields several names in a row.

def names
  yield "Ylva"
  yield "Brighid"
  yield "Shifra"
  yield "Yesamin"
end

The important thing to note about this method is that there is no looping or iteration going on here. It's just a simple straight-line series of yields.

Let's call this method, and supply a block which breaks as soon as it finds a name starting with 'S'.

names do |name|
  puts name
  break if name =~ /^S/
end
Ylva
Brighid
Shifra

Executing this code causes the first three lines of the names method to be evaluated. Once the break is hit, however, it is done. The method call is ended, and the last line will never be executed. So we can see already that break is about more than iteration; it can potentially halt the execution of any method which yields control to a block.

This might seem a little dangerous. What if we have a method that has some necessary cleanup to do once it is done executing? Just to illustrate, we'll add an ensure block to the end of the names method. It outputs one final name before exiting.

def names
  yield "Ylva"
  yield "Brighid"
  yield "Shifra"
  yield "Yesamin"
ensure 
  puts "Grimm"
end

When we call this with a block that just outputs yielded names, we can see that the last name is added at the end.

names do |name|
  puts name
end
Ylva
Brighid
Shifra
Yesamin
Grimm

OK, so what happens when we break out of the method early? To find out, we'll once again break if the name starts with 'S'.

names do |name|
  puts name
  break if name =~ /^S/
end
Ylva
Brighid
Shifra
Grimm

Because of the break, we didn't get any further than the name "Shifra"… but then the name "Grimm" was added at the end! What does this mean? It means that while break can end a method's execution early, it still respects ensure blocks. This is very similar to the way that exceptions terminate a method early, but still execute ensure blocks as they unwind the stack.

Let's summarize what we've learned so far:

  • break is not just for loops and iteration. It can force an early return from any method that yields.
  • And while break terminates the execution of a method, it still respects ensure blocks.

We're not done with break yet. In the next episode we'll look at using break to override a method's return value, and we'll work through a more realistic example. Until then, happy hacking!

Responses