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.

3 Comments
> # 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:
Speak your Mind
Preview