While working with and on Padre, the great Perl IDE, I discovered a possible bug: The shortcut F2 only worked once per Padre start. As I was busy working on something else, the issue went on the "verify and fix later" list. Today (the next morning), Gábor, the father of Padre, reported the same issue and this time I investigated it and found a common case causing very_hard_to_find errors.
Padre is using Actions for menu options, shortcuts, etc. The Action for showing the Perl help search (F2) is handled by the following piece of source:
for ( @{ $self->{event} } ) {
next if ref($_) ne 'CODE';
&{$_}(@args);
}
Once I verified that each F2 keypress reached this point by adding a debug print above the loop, the following debug prints got surprising results:
print "---START---\n";
for ( @{ $self->{event} } ) {
print STDERR $self->{name}." => $_\n";
next if ref($_) ne 'CODE';
&{$_}(@args);
}
This may trigger a "Use of uninitlized value" warning as "use warnings;" is active, but I don't care of them for debug prints which never reach the public. Anyway, here is the result:
---START---
help.search => CODE(0x9bcb9b0)
help.search => CODE(0xa2f8618)
---START---
help.search => -f
help.search => CODE(0xa2f8618)
We're walking through an array which isn't - believe me - touched anywhere, but the first value magically changes. Memory corruption? Human computer? Moon phase problems? No! It's the $_'s evil side. The fix was simple:
print "---START---\n";
for my $item ( @{ $self->{event} } ) {
print STDERR $self->{name}." => $item\n";
next if ref($item) ne 'CODE';
&{$item}(@args);
}
Here we go:
---START---
help.search => CODE(0x9bcb9b0)
help.search => CODE(0xa2f8618)
---START---
help.search => CODE(0x9bcb9b0)
help.search => CODE(0xa2f8618)
What happend?
$_ was used by the loop, but it was no copy of the first array item, it was referencing it. Because something in the called CODE(0x9bcb9b0) was using $_, the new value was stored into the referenced place - the first array item overriding it's own CODE-reference.
By using a private (my) variable for the loop, $_ isn't used any longer and the problem was gone: http://padre.perlide.org/trac/changeset/8727/trunk/Padre/lib/Padre/Action.pm
This is a common problem which triggers Perl newbies and experts and which is usually hard to find, because the errors occurs at a place somewhere later when using the modified data, but if you respect this rule, you should be safe:
Use a private my-variable for looping whenever you call a sub or method within your loop!