Daily Archives: July 30, 2011

Fun with the each function in Perl

I just had a fun time figuring out an odd bug with some code at work.

There was a loop something like,

my $var = $obj->meta->relationships;
while(my ($key, $val) = each %$var)
{
	warn $key;
	...
}

For some reason I wasn’t even seeing the warn $key being hit. I then debugged the code, had a look at var and stepped through and it worked perfectly. What the heck. What I’d have called a heisenbug before I looked up the term on Wikipedia and realised it’s a bit of a misnomer.

Technically it didn’t always work when I debugged, but if I examined the $var variable first it did. I then tried doing a warn Dumper $var; before the while and that made the code work regardless of the debugger. Now I was wondering what magic the dumping code did to the variable to the variable. Those of you familiar with the each function can probably guess. I wasn’t though so I rewrote the loop using a for and keys since I am more familiar with them and that fixed the code, without the need for a dump of the variable.

With the each looking like the culprit I then went hunting for the documentation. It turns out it’s a function so a perldoc -f each brings up it’s documentation. It turns out that this function uses an implicit iterator tied to the hash and is reset when the iterator ends, or when you call keys or values. That answered the question about my viewing the variable fixing the code. Dumper and the debugger must be calling keys in order to iterate over the hash to display it.

Given a general idea of how the function works I was then able to figure out how I’d create that sort of bug. Logically the each function must not have reached the end and reset itself after a previous loop. The most logical way to do that would be a last statement assuming the standard while(... each ...) type pattern was used everywhere. Sure enough, a grep of the source revealed a call in a different module which iterated over that hash using each and then broke out of the loop using last, i.e.

my $var = $obj->meta->relationships;
while(my ($key, $val) = each %$var)
{
	if($key eq $match)
	{
		last;
	}
	...
}

To fix that I could have called keys or values afterwards, but it struck me as more logical to simply change it to a for loop using keys instead,

for my $key (keys %$var)
{
	my $val = $var->{$key};
	...

This was a real head banger until I figured it out. The each function looks quite neat but it’s use of an implicit iterator means that while you can potentially do some very clever code, it also allows you to royally screw yourself over. Since I’m good enough at that already I think I’ll be avoiding the each function in general.

Tagged
Follow

Get every new post delivered to your Inbox.

Join 64 other followers