http://qs321.pair.com?node_id=660342

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I've exhausted my knowledge! Why does the first assignment to pkg1 work and the second assignment to the variable (pvar) not?

note that the "+++" print shows that pvar is the variable pkg2::VAR. i just can't assign to it.

I thought i could have a "simple" variable represent the ${ $var . "::VAR" } construct. thanks

:::::::::::::: pkgs.pm :::::::::::::: package pkgs; use strict; our $VAR="XXX"; package pkg1; our $VAR="YYY"; package pkg2; our $VAR="ZZZ"; 1; :::::::::::::: #!/tool/pandora/bin/perl -w use strict; use warnings; use pkgs; print "\n"; print "pkgs = ", $pkgs::VAR, "\n"; print "pkg1 = ", $pkg1::VAR, "\n"; print "pkg2 = ", $pkg2::VAR, "\n"; print "\n"; no strict "refs"; $pkgs::VAR = "00"; my $name = "pkg1"; ${ $name . "::VAR" } = 11; $name = "pkg2"; my $pvar = ${ $name . "::VAR" }; print "+++ $pvar\n"; $pvar = 22;print "pkgs = ", $pkgs::VAR, "\n"; print "pkg1 = ", $pkg1::VAR, "\n"; print "pkg2 = ", $pkg2::VAR, "\n"; print "\n"; use strict "refs";

Replies are listed 'Best First'.
Re: symbolic variables
by Fletch (Bishop) on Jan 04, 2008 at 00:48 UTC

    If by "second assignment" you mean my $pvar = ${ $name . "::VAR" };, all you've done is create a new lexical scalar with the value contained in the package variable $pkg2::VAR. There's nothing tying this new variable back to $pkg2::VAR.

    If that's what you wanted you'd either need to have a scalar reference my $pvar = \${ $name . "::VAR" };" and use that (${ $pvar } = 22), or make an alias to the original variable (local *pvar = \${ $name . "::VAR" }; $pvar = 22;).

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: symbolic variables
by Joost (Canon) on Jan 04, 2008 at 00:48 UTC
    note that the "+++" print shows that pvar is the variable pkg2::VAR. i just can't assign to it.
    It doesn't show that, it just shows that it contains the same value as $pkg2::var. You copied that value in the line above it. update: and you can assign to it: you even do so in your code. If you print the value of that var you can see that you are in fact modifying a copy.

    Try this and re-read perlref.

    no strict 'refs'; my $rvar = $name."::VAR"; $$rvar = 44; print $pkg2::VAR;
Re: symbolic variables
by Jenda (Abbot) on Jan 04, 2008 at 01:47 UTC

    If you are just being curious and playing with things, fine, but don't think of this as something you should do in production scripts. Outside obfuscation and golf consider symbolic references forbidden. You don't want to use them. You don't want to use them even by accident.

      yikes, i have to resort to them whenever i want to have "generic" logi +c that deals with a multitude of routines. i use symbolic references for : object methods dispatch tables and in most unit test scripts If you have a better alternative; i'll consider it!

      object methods : i use anonmyous routines for the methods that deal with scalar attributes.

      package <>; our $scalarMethods; @{ $scalarMethods } = qw( name ); foreach my $attributeScalar ( @{ $scalarMethods } ) { no strict "refs"; *$attributeScalar = sub { my $subName = $package . "::$attributeScalar"; if ($VRB) { print " $subName \n"; } my ($self) = shift; if (@_) { $self->{$attributeScalar} = shift; } return $self->{$attributeScalar}; } }

      dispatch tables : a generic manner to call routines in a package

      for ( $ndx=0; $ndx<=0; $ndx++ ) { no strict 'refs'; ($kgDATA,$pmDATA) = &{ "cktTmplt_utils::$SUB" }($ndx );

      unit test scripts : within the <>.t script

      # are package variables accessible ? no strict "refs"; foreach my $pkg ( @{ $filePackages } ) { for ( my $i=0; $i<=1; $i++ ) { ${ $pkg . "::VRB" } = $i; is( $i, ${ $pkg . "::VRB" }, "GLBL VAR : VRB" ); ${ $pkg . "::TST" } = $i; is( $i, ${ $pkg . "::TST" }, "GLBL VAR : TST" ); } ${ $pkg . "::VRB" } = 1; # no STDOUT durings tests ${ $pkg . "::TST" } = 1; # return data and don't execute } use strict "refs";

        Your first use to generate scalar methods is an OK use of symbolic references, because the way to create a named subroutine without using symbolic references is far more unwieldly:

        $::My::Package::{$attributeScalar} = sub {...};

        But why aren't you using Class::Accessor or any of the other modules which create such accessors for you?

        Using symbolic references in dispatch tables is convenient until you need to think about which subroutines are to be called dynamically and which not. Using hard references in a hash is self-documenting and more secure, and allows for renaming of the exported name:

        use vars qw(%user_methods); %user_methods = ( handle_foo => \&handle_foo, handle_bar => \&handle_bar, handle_baz => \&do_handle_baz, ); ... sub handle { my $data = shift; for my $filter (@_) { if (exists $user_methods{ $filter }) { $data = $user_methods{ $filter }->($data); } else { die "Unknown filter method '$filter'"; }; }; };

        Your third test will always succeed - you can always set global package variables. Also, I would ditch the C-style for loop in favour of:

        for my $i (0..1) {
Re: symbolic variables
by Anonymous Monk on Jan 04, 2008 at 01:32 UTC
    I am the seeker that asked this question. Thank you for your patience and support. I'm really appreciate your answers!