tags:

views:

72

answers:

3

I encountered some strange behavior which hints that I do not understand some basic things about Perl script execution and initialization order. The following example:

#!/usr/bin/env perl

use strict;
use warnings;

print &get_keys(), "\n";

use vars qw/%hello/;  # same effect with 'my %hello = (...);'
%hello = ( a => 1, b => 2 );

sub get_keys
{
        return join(', ', sort keys %hello);
}

prints an empty string. Meaning that though variable is already visible, since the state with assignment wasn't yet reached, it has no value. (Using a scalar instead of the hash would trigger a warning about uninitialized variable.)

Is that intended behavior?

I would be also glad for the RTFM pointers.

+3  A: 

The use vars pragma predeclares global variable name at compile time. The variable is undefined unless you assign any value to it. Since you print it before the assignment, you rightfully get an empty string.

BTW, this pragma is obsolete. From perldoc vars:

NOTE: For variables in the current package, the functionality provided by this pragma has been superseded by "our" declarations, available in Perl v5.6.0 or later. See "our" in perlfunc.

eugene y
Thanks for the `our` hint.
Dummy00001
+4  A: 

Yes, it's intended behaviour. You call get_keys() before you assign to %hello, so %hello is empty in get_keys(). (Scalars are initialised to undef, while arrays and hashes are set to be empty by default.)

If you want %hello to be initialised immediately, use a BEGIN block:

use vars qw/%hello/;
BEGIN {
    %hello = ( a => 1, b => 2 );
}

Note that if you were using my (or our, for that matter) then this wouldn't work:

BEGIN {
    my %hello = ( a => 1, b => 2 );
}

because you have to declare the variable outside the block, like so:

my %hello;
BEGIN {
    %hello = ( a => 1, b => 2 );
}
Dave Hinton
+8  A: 

From perlsub:

A my has both a compile-time and a run-time effect. At compile time, the compiler takes notice of it. The principal usefulness of this is to quiet use strict 'vars' .... Actual initialization is delayed until run time, though, so it gets executed at the appropriate time.

# At this point, %hello is a lexically scope variable (the my took effect
# at compile time), but it still has no keys.
print get_keys();

my %hello = ( a => 1, b => 2 );

# Now the hash has content.
print get_keys();

sub get_keys { join ' ', keys %hello, "\n" }

Other notes: (1) You should be using my or our rather than use vars. (2) Under normal circumstances, don't call functions with a leading ampersand: use foo() rather than &foo().

FM