in reply to Re: Is 'use vars' really obsolete?
in thread Is 'use vars' really obsolete?

I ran into a case in a module where I had 'use vars' and I changed it to 'our' causing it to break.

It was in an export module that exports a variable to the caller's package. I had:

my $code = 'package '.$pkgnam.'; use vars qw($'.$varname.'); $'.$varname.' = "'.$value.'"; '; eval $code; $@ and die "Error in exporting var $varname: $@";
and had changed it to:
my $code = 'package ' . $pkgnam . '; our $'.$varname.' = "'.$value.'"'; eval $code; $@ and die "Error in exporting var $varname: $@";
As a sample varname, I had 'Tor_mgr' being exported back to the using prog. After the change, in the using prog, I got:
Variable "$Tor_mgr" is not imported at ./rss_rdr line 724. Variable "$Tor_mgr" is not imported at ./rss_rdr line 736. Variable "$Tor_mgr" is not imported at ./rss_rdr line 745. Global symbol "$Tor_mgr" requires explicit package name at ./rss_rdr l +ine 724. Global symbol "$Tor_mgr" requires explicit package name at ./rss_rdr l +ine 736. Global symbol "$Tor_mgr" requires explicit package name at ./rss_rdr l +ine 745. BEGIN not safe after errors--compilation aborted at ./rss_rdr line 754 +.
What I think was happening, is that the processing of the module didn't happen until after the prog had already been through the 'BEGIN' stage, so this module couldn't insert the 'our' definition in the package's namespace before its usage, so in the 2nd pass, perl saw $Tor_mgr which it now new to be defined later on, but didn't see it in an EXPORT array in the used module (I'm guessing). Anyway, since the 'use vars' was in the first version, that defined it in a non-lexical scope, which passes the 2nd pass's checks.

It may be that the module could be rewritten to not need use vars, but it doesn't look straight forward.

FWIW, the module being used, exported variable names with values corresponding to found paths of their lower-case names as executables, so any EXPORT list would be variable per usage (though fixed per program invocation).

Replies are listed 'Best First'.
Re^3: Is 'use vars' really obsolete?
by LanX (Saint) on Sep 22, 2017 at 01:38 UTC
    That's lots of voodoo. ..

    the effect of our will be restricted to the eval, I'm not sure how far use vars go.

    I'd say it's globally effective whenever the same package is chosen.

    (but I'm not really trying to understand what is happening during an export here. :)

    edit

    OK I think I have an idea what is happening here and I think the author should have a look into Exporter, IIRC exporting package-vars is part of the specification.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      > I'd say it's globally effective whenever the same package is chosen.

      Basically yes.

      I had a look into the code of vars and found this discussion Confused by symbol table import mechanism of 'use vars'

      What's happening is a "fake" import:

      *Target::x = \$Target::x;

      Importing means that in the symbol table of the target package a glob is assigned to an external reference.

      But in this case it's just a self reference to its own package. (Granted, this looks a bit confusing... *)

      Like this strict doesn't complain when seeing an unqualified $var inside package Target because it's already imported into Target's STASH.

      To answer the OP, this has global effect while our is tightly scoped.

      And the use case you've shown is just a quite complicated way to export.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

      *) the symbol table decides which variables, functions, file handles and formats are known to the package without needing to be fully qualified.

      Did you catch the last line of my post:
      FWIW, the module being used, exported variable names with values corresponding to found paths of their lower-case names as executables, so any EXPORT list would be variable per usage (though fixed per program invocation).

      I didn't think Exporter would work in this case because, 1) I'm not exporting anything, and 2) the programs using the module get differently named IMPORTS based on what they pass (not based on anything in the used module -- i.e. I'm not exporting any package variables.

      Example: I had a program that created file-system snapshots. In main I needed to call ~10 external programs, so I had:

      use Cmds qw(sudo dd rsync dmsetup lvremove touch cp rm mount umount +);
      In places in the program where I wanted to call a program, I'd construct a command. Since the program ran part-time as root, I wanted to make sure that common commands resolved to the real commands in the right places. Additionally, I didn't want it to fail unpredictably -- but instead fail at startup there would be no changes to the system state. In the above usage, Cmds uses a safe internal path and then puts variables containing the absolute paths of the commands into the caller's package name space. The variables never exist in Cmds, so I don't see that Exporter would even work in this case.

      The calling program would reference the external command paths by using the up-cased name of the command as a variable. Example:

      open ($fh, "|$Sudo $Dd conv=fsync of=$fn 2>/dev/null");
      So Cmds allows me to call external commands, safely, using builtin paths, allows me to use those paths via variables that can be used in strings, and ensures presence of needed external commands before running the program.

      As for the use case being complicated, it was easier to make work 7 years ago than other methods. I just ran across it when checking something out in the module and it seemed like an interesting case where 'our' wasn't an easy replacement for use vars.