Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Note on usage of ours variables and a question

by likbez (Sexton)
on Nov 19, 2019 at 22:27 UTC ( #11108913=perlquestion: print w/replies, xml ) Need Help??

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

I would like to avoid qualification with package name a variable that I use in many modules in many situations. For example, variable debug.

Looks like I can't use our declaration for this purpose (see below) Does any other mechanism exist?

Also question about 'export" behavior". If I export variable debug from module A does it became "normal variable" in main:: so that I can use it in module B? what will happen if I export it from module b as well ? It should bind it to the same variable, right?

Can anybody enlighten me about this behavior? BTW does Perl have a system variable "debug" that is global and does not need qualification with the package name?

For example, if I created module example.pm it compiles OK, but produces a run time error because Perl assumes that our debug is $example::debug not $main::debug

May be our behavior can be generalized to handle this case as well? Why we can't alias variables in other namespaces? Is not this an artificial restriction?

package example; use v5.10; use warnings; use strict 'subs'; use feature 'state'; require Exporter; our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); @ISA = qw(Exporter); $::debug=1; { our $debug; say "debug=$debug"; } $VERSION = '1.10'; 1; and the test script: <code> #!/usr/bin/perl #:: test of ours use v5.10; use warnings; use strict 'subs'; use feature 'state'; use lib '.'; use example; say "debug=$debug";
It complains that it is undefined:
[255] # perl test_our_behaviour.pl <code> [0] # perl test_our_behaviour.pl Use of uninitialized value $example::debug in concatenation (.) or str +ing at example.pm line 14. IN EXAMPLE: debug= debug=1

Replies are listed 'Best First'.
Re: Note on usage of ours variables and a question
by hippo (Bishop) on Nov 19, 2019 at 22:56 UTC

    Here is a replacement for your module and script showing one way of achieving this.

    use strict; use warnings; package Example; use parent 'Exporter'; our ($VERSION, @EXPORT, $debug); $VERSION = '1.0'; @EXPORT = qw($debug); $debug = 1; 1;
    #!/usr/bin/env perl use strict; use warnings; use lib '.'; use Example; print "debug = $debug\n";

    I've removed a lot of your boilerplate for clarity. I've also adhered to convention and capitalised the module name. Note that filling @EXPORT is generally frowned upon. Much better to use @EXPORT_OK and allow the script to decide which symbols to import.

    BTW does Perl have a system variable "debug" that is global and does not need qualification with the package name?

    No, but it does have the warnings pragma and $^W which you might consider similar. I'd stick with your own flags unless you have a good reason to do otherwise, though.

      > Note that filling @EXPORT is generally frowned upon. Much better to use @EXPORT_OK and allow the script to decide which symbols to import.

      I agree, but the road to hell is paved with good intentions. It depends whether modules in question are written as reusable or not. My are not. Intentionally. One advantage of using export is that there can't be mismatch between your intentions and actually exported variables. Which you will discover several months down the road. Been there, done that.

      Also for some idiosyncratic reasons I consider this quest for reusability as often misguided obsession, which cost you a lot of man hours with zero return.

      Even slight adaptation of module to the task in hand cuts the code lines in half in comparison with using a "universal/reusable" version. Number of errors in your code is generally proportional to the number of codeines. And life is short. It is something similar with polishing your OO classes instead of doing productive work. Or converting your perfectly valid procedural version into the OO version, because everybody are using OO.

Re: Note on usage of ours variables and a question
by haukex (Bishop) on Nov 19, 2019 at 23:01 UTC

    I think the best approach depends on the specific application, which you haven't described very much. Of course TIMTOWTDI, but I would suggest that instead of the modules exporting a debug variable or something similar, the main script should instead set the debug flag on the module. So for example, if I write OO classes, I might give the constructor a debug argument that is set based on a $DEBUG package variable in the main script. If it's a simple module, it might have its own our $DEBUG variable in its package, and then the main code could do $Module::Name::DEBUG = $DEBUG. This will allow you to use the $DEBUG variable name everywhere, and still keep the possibility of somewhat more fine-grained control, instead of one global debug flag that enables debug messages everywhere. So like this is how I typically do it:

    use warnings; use strict; use Getopt::Long; GetOptions( 'd|debug' => \(our $DEBUG) ) or die "Bad options\n"; $Foo::DEBUG = $DEBUG; print "Debugging main\n" if $DEBUG; Foo::foo(); my $bar = Bar->new( debug => $DEBUG ); $bar->quz(); { package Foo; our $DEBUG; sub foo { print "Debugging Foo\n" if $DEBUG; } } { package Bar; sub new { my ($class,%args) = @_; my $self = { %args }; return bless $self, $class; } sub quz { my $self = shift; print "Debugging $self->quz()\n" if $self->{debug}; } }
    Also question about 'export" behavior". If I export variable debug from module A does it became "normal variable" in main:: so that I can use it in module B? what will happen if I export it from module b as well ? It should bind it to the same variable, right?

    If I understand your question correctly, then no, two different exports will overwrite each other. If you have a module X with our $Z that gets exported to main, and then a module Y with our $Z that also gets exported to main, the second export will clobber the first. Consider that you've got two variables, one in each package, and so the variable $main::Z can only be an alias for one or the other.

    use warnings; use strict; BEGIN { package X; use me::inlined; # alternative: $INC{__PACKAGE__.'.pm'}=$0; use Exporter 'import'; our @EXPORT = qw/$Z/; our $Z = 'from '.__PACKAGE__; } BEGIN { package Y; use me::inlined; # alternative: $INC{__PACKAGE__.'.pm'}=$0; use Exporter 'import'; our @EXPORT = qw/$Z/; our $Z = 'from '.__PACKAGE__; } use X; use Y; print "$Z\n"; # prints "from Y"

    Although I wouldn't recommend it (!), you could have all your modules reference $main::DEBUG with the shorthand $::DEBUG, or even alias the package variables to $main::DEBUG, then you'd only have one central variable. However, the problems with this are that you lose the fine-grained control of the debug flag, and also if these modules are loaded into code that doesn't know about their behavior (remember modules are meant to be re-used), things might break when those modules reach outside of their package into variables that aren't really theirs.

    Can anybody enlighten me about this behavior?

    I would suggest a careful read of the sections "Packages" and "Symbol Tables" in perlmod (the rest of the document is also very interesting).

    BTW does Perl have a system variable "debug" that is global and does not need qualification with the package name?

    No, not that I'm aware of in the core.

    Why we can't alias variables in other namespaces? Is not this an artificial restriction?

    It's possible - you'd have to show an instance of where it isn't working for you.

Re: Note on usage of ours variables and a question
by tobyink (Canon) on Nov 19, 2019 at 23:33 UTC

    The following is a very, very stupid idea, but it does work.

    ${^MYDEBUG} = 1;

    Variables written like that (names starting with a "^" sign and in braces) are automatically global and available everywhere in your program, without needing to be declared.

    Have fun!

      Variables written ... with a "^" sign and in braces ... are automatically global and available everywhere in your program, without needing to be declared.

      So is any fully-qualified package-global (even under strictures):

      c:\@Work\Perl\monks>perl -wMstrict -le "{ package Foo; $::bar = 'Baz'; sub p_bar { print $::bar; } } ;; Foo::p_bar; ;; { package Fiz; sub new_bar { $::bar = 'Boff'; } } Fiz::new_bar; Foo::p_bar; ;; $::bar = 'Quux'; print $::bar; " Baz Boff Quux


      Give a man a fish:  <%-{-{-{-<

      Hi Toby,

      Amazing finding !

      ${^MYDEBUG} = 1;
      This does solves that problem. So you are the first to provide a real solution. Kind of undocumented feature. Thank you very much.

      But the problem is that I often forget to put :: after $ and correcting this error ( as in "$debug -> $::debug ") takes my time and if you have many modules and change debugging statements in them often it became pretty annoying because for me this error is persistent.

      This is even more complex idiom and I unfortunately I am very bad with typing them. I still often type variables without sigil, especially if the same day I used C.

      But in any case I did learn something new and interesting about Perl today. Thanks again.

Re: Note on usage of ours variables and a question
by BillKSmith (Monsignor) on Nov 19, 2019 at 23:19 UTC
    I recommend that you imitate the "Configuration Variables" in the frequently used module Data::Dumper.
    Bill
Re: Note on usage of ours variables and a question -- ENV
by Discipulus (Abbot) on Nov 20, 2019 at 20:18 UTC
    Hello likbez,

    you already received many good options and approaches, but your:

    > BTW does Perl have a system variable "debug" that is global and does not need qualification with the package name?

    prompts me for another answer: yes! you have %ENV at your disposal and you can create your own varaiable like DEBUG_TEMP that is uber global

    #cat Example.pm package Example; use strict; use warnings; sub my_test{ print "output from sub\n"; print "package ",__PACKAGE__," spot debug!!\n" if $ENV{DEBUG_T +EMP}; } 1; #cat test-env.pl use strict; use warnings; use lib '.'; use Example; Example::my_test(); # test without the var $ENV{DEBUG_TEMP} = 1; Example::my_test(); # test with the var #perl test-env.pl output from sub # output before var setting output from sub # two lines after var setting package Example spot debug!! # when the program exits, DEBUG_TEMP disappears #perl -I . -MExample -e "Example::my_test()" output from sub

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Note on usage of ours variables and a question
by LanX (Sage) on Nov 20, 2019 at 17:52 UTC
    > I would like to avoid qualification with package name a variable that I use in many modules in many situations. For example, variable debug.

    TIMTOWTDI

    The following makes the variable $Debug::DEBUG available as $DEBUG for the rest of the file

    use strict; use warnings; package Debug; our $DEBUG; package MyPkg; print $DEBUG if $DEBUG;

    but I'd rather use a constant.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: Note on usage of ours variables and a question
by karlgoethebier (Abbot) on Nov 21, 2019 at 16:49 UTC

    You want a constant? Or you may try the There Can Be Only One approach 😎. Log::Log4perl does it do like this. Or offers it. As you like. And/or as far as i remember. Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (6)
As of 2021-10-25 12:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My first memorable Perl project was:







    Results (89 votes). Check out past polls.

    Notices?