Perl vs. Ruby breaking from nested loops
Breaking out of nested blocks is apparently done much differently in Perl and Ruby. In Perl if you run this:
my $counter = 0; foreach my $outer (1..5) { foreach my $inner ('A'..'E') { print "$outer: $inner\n"; last if ++$counter > 4 } }
The last is going to break out of the inner-most foreach loop by default. If you want to break out of the OUTER foreach loop you can use line labels:
my $counter = 0; OUTER: foreach my $outer (1..5) { foreach my $inner ('A'..'E') { print "$outer: $inner\n"; last OUTER if ++$counter > 4 } }
In Ruby to do the same thing, you have to use a throw/catch block. This is a completely separate mechanism from Ruby's begin/rescue Exception-handling mechanism. throw/catch rather appears to be simply a flow-control mechanism. You raise Exceptions, but you throw Strings or Symbols. The equivalent of the above Perl in Ruby:
counter = 0 catch :OUTER do 1.upto(5) do |outer| 'A'.upto'E' do |inner| puts "#{outer}: #{inner}" throw :OUTER if (counter += 1) > 4 end end end
EDIT: Originally I thought that Perl's last LABEL; would not find labels except in the same static scope. It must've been a bug in my test code however, because this does work. My mistake! So this does work in Perl:
sub test { HERE: foreach my $really_outer (1..5) { test2(); } } sub test2 { my $counter = 0; foreach my $outer (1..5) { foreach my $inner ('A'..'E') { print "$outer: $inner\n"; last HERE; } } } test
You can do this in Ruby also. The other nice thing about Ruby is you can return a value from the throw:
def test result = catch :HERE do 1.upto(5) do |really_outer| test2 end end puts "RESULT: #{result}" end def test2 counter = 0 1.upto(5) do |outer| 'A'.upto'E' do |inner| puts "#{outer}: #{inner}" throw :HERE, "YOINK" if (counter += 1) > 4 end end end test
In Perl you also have the option of using Error.pm, but it looks horrendously hackish to me, as Perl code often does.
The only thing I can think of that's bad about Ruby is that it has two things which are really similar, one for Exceptions and one not. People coming from a different language may think that throw/catch is the Exception-handling mechanism when it's not. But Ruby still wins here.

> # How do you break to HERE?????
WTF??? How about “last HERE;”? RTFM.
I was wrong, it does work in Perl. Thanks for pointing it out. You are incredibly rude, however. Please learn how to interact with other human beings in a polite manner. :)
Why you need Error.pm? You can do both with stock perl5, the quite ugly exception-style and using a
return value from the throw:
my $counter = 0;
eval {
foreach my $outer (1..5) {
foreach my $inner ('A'..'E') {
print “$outer: $inner\n”;
die { message => “jump out!” } if ++$counter > 4
}
}
};
use Data::Dumper; print Dumper $@;