I hit a bug in a script I was writing this week which reminded me that sometimes you can put too much faith in perl’s ability to ‘do what I mean’ (DWIM). It took me a couple of minutes to see what was going wrong here – see if you do any better.
#!/usr/bin/perl use warnings; use strict; my $data; populate_data($data); print_data($data); sub populate_data { my ($d) = @_; $d->{somekey} = 'somevalue'; } sub print_data { my ($d) = @_; if (exists $d->{somekey}) { print 'Win!'; } else { die 'Fail!'; } }
No errors, no warnings, but epic fail.
One of the things which confuses people learing perl is the creation of complex data structures and autovivication. That is to say if you treat a scalar as a reference to an array of array of array of arrays (for example), then that’s exactly what it becomes – you don’t need to explicitly define the structure as it is all created on the fly.
In this case though I was expecting too much. When the $data variable is first created it has an undefined value. When I pass it into the subroutine all that is passed is the undefined value. Adding data to the undefined value autovivifies the expected data structure, but since this was created in the subroutine there’s no way for that to propogate back to the calling code.
The answer is to define at least the top level of structure before calling the populate_data subroutine. That way you are passing in a valid reference to the subroutine (where further structure can be added), but the data is added to an anonymous data structure which is still referred to in the calling code.
The simple fix is therefore to make the initial declaration of $data be:
my $data = {};
..and Fail becomes Win.