I've known but never used Ruby's catch and throw until tackling an Advent of Code problem. This particular challenge had me building multiple nested iterators, in short scanning a 3d array – a set of game boards which contain rows which contain cells.

boards.each do |board|
board.each_with_index do |row, row_idx|
row.each_with_index do |col, col_idx|
# if <condition> exit all the enumerators
end
end
end

So the question was, how to simply break out of all the iterators if a condition was met on line 4. One simple way to do this would be to factor this block out to a method and have a return statement here but there is another way.

While ruby does have first-class support for exception handling, catch and throw are not used for exceptions but for control-flow. They are made for exactly the problem I'm trying so solve; breaking out of a stack several levels deep and returning control to the a point much earlier.

This is what they look like:

catch(:something) do
loop do
throw :something
end
end

The throw statement immediately returns to calling block. In fact we can use this to return values to the outer block

value = catch(:something) do
loop do
throw :something, 'foobar'
end
end

Here, value will become equal to foobar at the point line 3 executes.

This helps me write my block like this:

score = catch(:won) do
boards.each do |board|
board.each_with_index do |row, row_idx|
row.each_with_index do |col, col_idx|
# do some work
throw :won, some_value if condition
end
end
end
end

The full block of code is on GitHub.