LaunchKit
All quizzes
Ruby 0 views

Giving break a return value

Question

What's the return value of the following Ruby code?

(1..10).each { |n| break n if n == 5 } # => ???

The correct answer is

Explanation

TL;DR

break exits the enclosing iterator immediately, and any argument you give it becomes the return value of the whole method call. When n reaches 5, break n terminates each and makes it return 5. Without the break, each would have returned its receiver, the range itself.

Step by step

The block runs for n = 1, 2, 3, 4 without effect. At n = 5, the condition is true and break n fires: iteration stops (6 through 10 are never yielded) and 5 becomes the value of the each expression.

The variants make the rule visible:

(1..10).each { |n| break n if n == 5 }   # => 5
(1..10).each { |n| break if n == 5 }     # => nil
(1..10).each { |n| break 42 if n == 5 }  # => 42
(1..10).each { |n| n }                   # => 1..10

A bare break returns nil. break 42 returns 42; the argument is arbitrary, not tied to the block parameter. And with no break at all, each runs to completion and returns the receiver.

The same rule applies to any method that yields, not just each. A break out of map discards the partial result and returns the break value:

(1..10).map { |n| break n if n == 5; n * 2 } # => 5

break vs next

next is the local counterpart: it ends only the current block invocation, and its argument becomes the value of that single yield:

(1..4).map { |n| next 0 if n.odd?; n * 10 } # => [0, 20, 0, 40]

break answers for the whole method call; next answers for one iteration.

The idiomatic spelling

"Stop at the first element matching a condition and return it" already has a name, Enumerable#find:

(1..10).find { |n| n == 5 } # => 5

break with a value earns its place when you need to short-circuit an iterator that find cannot express, such as bailing out of each_slice or a nested loop with a computed result.

Share this quiz

Comments

No comments yet. Be the first.

Only used to confirm and publish your comment. Never shown publicly, never shared.

Markdown: **bold**, `code`, ```fenced blocks```, > quotes, [links](url). HTML and images are not rendered.