Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re: What does use vars qw{$VERSION}; do?

by davido (Cardinal)
on Oct 31, 2016 at 05:09 UTC ( [id://1174988]=note: print w/replies, xml ) Need Help??


in reply to What does use vars qw{$VERSION}; do?

The source code for vars is not totally impenetrable. The first thing to recall is that use Foo qw(bar); is essentially the same thing as:

BEGIN{ require Foo; Foo->import('bar'); }

And the brief explanation of what import() typically does, is it makes some thing available within the caller's namespace. It exports something. In the case of my example, it exports a subroutine (probably) named bar. In the case of use vars qw($foo), it exports into the caller's namespace a package global scalar variable named $foo.

Now let's look at the import function from vars, which is invoked when use vars qw(...) is called:

sub import { # Determine the package name of the caller. my $callpack = caller; # Grab the list of symbols that need to be exported. my (undef, @imports) = @_; my ($sym, $ch); foreach (@imports) { # For each "var", find the sigil and the symbol. if (($ch, $sym) = /^([\$\@\%\*\&])(.+)/) { # If the symbol contains non-word characters... if ($sym =~ /\W/) { # time for a more-detailed check-up if ($sym =~ /^\w+[[{].*[]}]$/) { # We're being asked to declare an array or hash el +ement. That's not cool. require Carp; Carp::croak("Can't declare individual elements of hash or +array"); } elsif (warnings::enabled() and length($sym) == 1 and $sym !~ + tr/a-zA-Z//) { # If it's a special punctuation variable... warnings::warn("No need to declare built-in vars"); } elsif (($^H &= strict::bits('vars'))) { # If we're strict, disallow funky variable names. require Carp; Carp::croak("'$_' is not a valid variable name under stric +t vars"); } } # Build up the fully-qualified symbol name. $sym = "${callpack}::$sym" unless $sym =~ /::/; # Vivify the symbol name within the appropriate package/na +mespace. *$sym = ( $ch eq "\$" ? \$$sym : $ch eq "\@" ? \@$sym : $ch eq "\%" ? \%$sym : $ch eq "\*" ? \*$sym : $ch eq "\&" ? \&$sym : do { require Carp; Carp::croak("'$_' is not a valid variable name"); }); } else { # This is odd... we weren't given a sigil. require Carp; Carp::croak("'$_' is not a valid variable name"); } } };

That's it... some heuristics to decide what the fully qualified variable name should be, and then a little bit of symbol table trickery to make it exist.

use vars is useful because it makes the variable exist so that strict 'vars' doesn't get angry. It's an early form of pre-declaration. Other forms of pre-declaration include my and our. The first one (my) creates a lexical variable. our creates a package global and makes it available without using a fully qualified name, within the lexical scope in which our was invoked. vars is mostly oblivious to lexical scoping. It creates package globals, that's it.

The BEGIN block is usually used to control the order in which things happen as compiletime gets underway. By using vars in a begin block, most likely the author intended to have it happen in a specific order. use already happens during compiletime, but the BEGIN block can be used to fine tune the sequence of compiletime events.

I don't usually do "disclaimers", but... The dark art of symbol table manipulation and compiletime manipulation is difficult to express both in layman's terms and at the same time with sufficient precision as to not misrepresent anything. I apologize in advance if this post falls short in either endeavor.


Dave

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1174988]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-19 04:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found