SoFunction
Updated on 2025-04-07

Tutorial on Usage of Interrupts and Returns in Ruby Programming

The use of keywords such as return, break, and next involves the issue of breaking out of scope, and their differences lies in the different scopes of different keywords, because there are code blocks that require special attention.
return
Common ways

Usually the return statement is the same as everyone understands.

def m1 param
 if param == 1
  return 'returned 1'
 end
 'returned default value' # According to Ruby language specification, the result of the last execution statement will be returned as the return value, return is optionalend

m1(1) # => returned 1
m1(2) # => returned default value

When there is an exception-catching guarantee, the situation will be slightly different:

def m1
 'return default'
ensure
 puts 'I am sure that it will be here!'
end

m1 # => return default

In this case, before the ensure statement, whether it is displayed or not, the m1 method will return the value before ensure. The guarantee statement just ensures that the subsequent code block puts 'I am sure that it will be here!' is executed, but it will not be returned from here. If the return is used to return the value displayed in the ensure statement, the situation will be different. Examples are as follows:

def m1
 return 'return default'
ensure
 return 'I am sure that it will be here!'
end

m1 # => I am sure that it will be here!

Regardless of whether the return is displayed before ensure, the value after ensure will be returned.

In case of code block intervention, it will be different:

def m1
 p 'start ... '
 proc do
  p 'block start'
  return
  p 'block end'
 
 p 'end ... '
end

m1

# Output result:#
# "start ... "
# "block start"

This should be expected, let's look at the next one:

def m1
 p 'start ... '
 -> do
  p 'block start'
  return
  p 'block end'
 
 p 'end ... '
end

m1

# Output result:#
# "start ... "
# "block start"
# "end ... "

There is an extra line "end..." here, why? This is the biggest difference between Proc and Lambda. Among them, the return statements have different scopes. Proc will directly jump out of the entire method call, while Lambda will only jump out of its own scope and return to the method to continue execution. This requires special attention. (In break, the way Proc and Lambda jumps out is the same as return, so I won't go into details later.)
break

Let’s take a look at a simple example:

result = [1, 2, 3, 4, 5].map do |i|
 i * 2
end

p result # => [2, 4, 6, 8, 10]

This is nothing strange, so look at the following one and guess what its output is?

result = [1, 2, 3, 4, 5].map do |i|
 break if i > 3
 i * 2
end
# FLAG
p result

Is it [1, 2, 3, nil, nil]? Or [1, 2, 3]? Or something? The answer is nil, because after executing break, it jumps directly to FLAG, which means that the map method is jumped out. The statement in the map method has not been executed, resulting in no return value. In order to verify that this idea is correct, we can use the Ruby language break that can have return value to verify:

result = [1, 2, 3, 4, 5].map do |i|
 break 'returned break' if i > 3
 i * 2
end

p result # => "returned break"

Here we can prove that our guess is correct. Although the above explains this issue, it should not be very easy to understand. Let’s define a code block ourselves, let’s explain it:

def m1
 p 'start in m1 ... '
 m2 do # Code Block  p 'start in block in m1 ... '
  p 'end in block in m1 ... '
 end
 p 'end in m1 ... '
end

def m2 &block
 p 'start in m2 ... '
 
 p 'end in m2 ... '
end

m1

# Output result:#
# "start in m1 ... "
# "start in m2 ... "
# "start in block in m1 ... "
# "end in block in m1 ... "
# "end in m2 ... "
# "end in m1 ... "

Then we add break to the block in m1 to see the execution result:

def m1
 p 'start in m1 ... '
 m2 do # Code Block  p 'start in block in m1 ... '
  break
  p 'end in block in m1 ... '
 end
 p 'end in m1 ... '
end

def m2 &block
 p 'start in m2 ... '
 
 p 'end in m2 ... '
end

m1

# Output result:#
# "start in m1 ... "
# "start in m2 ... "
# "start in block in m1 ... "
# "end in m1 ... "

You can see that the last line of code in the code block is not executed, and the last line of m2 is not executed, because this line is not executed, the map in the second example of break does not return any value. To sum up, the break in the code block will directly jump out of the called method (m2), and continue to execute the remaining statements in this method (m1) in the method (m1) that declares the code block.
next

The next keyword is similar to continue in other languages, and it works basically similar to continue.

def m1
 p 'start in m1 ... '
 m2 do # Code Block  p 'start in block in m1 ... '
  next
  p 'end in block in m1 ... '
 end
 p 'end in m1 ... '
end

def m2 &block
 p 'start in m2 ... '
 
 p 'end in m2 ... '
end

m1

# Output result:#
# "start in m1 ... "
# "start in m2 ... "
# "start in block in m1 ... "
# "end in m2 ... "
# "end in m1 ... "

Just skimming the last line of code in the code block, this is how next works. Let’s take a look at the example of break. If you write it in next, what will be the result? If you fully understand what is written above, I believe you can calculate the results in your brain:

result = [1, 2, 3, 4, 5].map do |i|
 next if i > 3
 i * 2
end

p result # => [2, 4, 6, nil, nil]

Next statement can also have a return value:

result = [1, 2, 3, 4, 5].map do |i|
 next 'next' if i > 3
 i * 2
end

p result # => [2, 4, 6, "next", "next"]

other

For return, both in the method and in the code block, while break and next can only be used in the code block (it can also be used in the loop structure, but generally it is also represented in the form of the code block). If you call both in the method, you will prompt a syntax error, that is:

def m1
 return # OK
 break # Invalid break, compile error (SyntaxError)
 next  # Invalid next, compile error (SyntaxError)
end

in conclusion

return is the same as other languages ​​in most cases, and attention should be paid to the details in two different code blocks: ensure and Proc and Lambda.

break needs to be noted in code blocks in which there are methods nested calls, it always returns to the method that calls the code block method (a bit of a twist).

next is the most honest, basically nothing to pay attention to.

Finally, not only return can return, but break and next can return values.