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

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

Hi Monks,

This one escapes me:

#!/usr/bin/perl use strict; my $debug=1; if ($debug > 0) { use warnings; print "Using warnings\n"; } run_sub(); sub run_sub { print "Running\n"; } sub run_sub { print "Ran\n"; }

Am expecting a warning...? Thanks for considering.

~

Replies are listed 'Best First'.
Re: use of "use X"
by ikegami (Patriarch) on Jan 18, 2012 at 06:38 UTC
    use warnings;

    is short for

    BEGIN { require warnings; import warnings; }

    so you could do

    BEGIN { my $debug = 1; if ($debug) { require warnings; import warnings; } }

    The if module attempts to clean that up:

    my $debug; BEGIN { $debug = 1; } use if $debug, 'warnings';
Re: use of "use X"
by BrowserUk (Patriarch) on Jan 18, 2012 at 01:53 UTC

    warnings is lexically scoped.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: use of "use X"
by toolic (Bishop) on Jan 18, 2012 at 02:28 UTC
Re: use of "use X"
by TomDLux (Vicar) on Jan 18, 2012 at 01:57 UTC

    By the way, you need to hide the 'use module' within an eval, to control whether it happens or not, or else use the module 'if' ( use if CONDITION, MODULE => ARGS ).

    As Occam said: Entia non sunt multiplicanda praeter necessitatem.

      Using eval would delay the directive to runtime, but it needs to be active at runtime to affect code.

      >perl -e"eval 'use warnings; 1' or die $@; print undef;" >perl -e"use warnings; print undef;" Use of uninitialized value in print at -e line 1.

      And you can't wrap it in a BEGIN because that would introduce a lexical scope.

Re: use of "use X"
by Khen1950fx (Canon) on Jan 18, 2012 at 08:29 UTC
    I took your idea, following ikegami's advice, and wrote a test.
    #!/usr/bin/perl -l use strict; use CGI; use Test::SubCalls; use Test::More tests => 2; BEGIN { my $debug = 1; if ($debug) { require warnings; import warnings; } } print "Using warnings"; sub_track( 'CGI::new' ); my $q1 = CGI->new; my $q2 = CGI->new; sub_calls( 'CGI::new', 2, "Running" ); sub_calls( 'CGI::new', 2, "Ran" ); done_testing(2);
Re: use of "use X"
by JavaFan (Canon) on Jan 18, 2012 at 10:07 UTC
    BEGIN { my $debug = 0; unless ($debug) { $INC {"warnings.pm"} = 1; no strict 'refs'; *{"warnings::import"} = sub {1;}; } } use warnings;
    Of course, that will prohibit warnings to be turned on from anywhere in your program.

    If you can live with just one category enabled if debugging is off, you could do:

    BEGIN { $::DEBUG = 1; } use warnings $::DEBUG ? "all" : "io"; # Or some other category.
Re: use of "use X"
by bbfan (Novice) on Jan 18, 2012 at 04:52 UTC
    Thanks for the suggestions folks. No luck finding a solution; am thinking it may not be possible. Although this works:

    use if (1 == 1), warnings => qw(all);

    am thinking that an eval on $debug *requires* the compiler, therefore compiler directives like "strict, warnings, diagnostics, etc." cannot be loaded in this manner (however, I'm often wrong). For more, see:

    http://www.perlmonks.org/?node_id=323606

      I think what you were looking for is

      $ perl -E 'BEGIN {our $debug = 1;} use if $debug // 0, warnings; say u +ndef' Use of uninitialized value in say at -e line 1.

      although I would be inclined to go with an environment variable instead, to avoid having to edit the source code:

      $ debug=1 perl -E 'use if $ENV{debug} // 0, warnings; say undef' Use of uninitialized value in say at -e line 1.
Re: use of "use X"
by Anonymous Monk on Jan 18, 2012 at 16:01 UTC

    To a certain extent, the use declaration is, shall we say, “overloaded.”   In some ways it is a lot like require, whereas in other ways it absolutely is not.   Here is another case where Perl might have infuriated semantic purists, in favor of being a pragmatically useful tool.   I suggest that you always treat the statement as a declaration, not as an executable statement.   Put all of the necessary declarations at the beginning of the module (beginning always with use strict; use warnings;), and leave them there.

Re: use of "use X"
by Anonymous Monk on Jan 18, 2012 at 19:28 UTC
    Wow! What a great response. Thank you all for the insights!!

    Am much closer to the goal, now just stuck on the "inverse, sort of" (from the Camel Book) of "use", "no". Sorry, not meaning to be cryptic. Instead, here's some code that demonstrates what I was hoping to achieve:

    use strict; my $debug; BEGIN { $debug = 3; } use if ($debug > 0), 'warnings'; use if ($debug > 1), 'diagnostics'; if ($debug > 2) { no warnings 'redefine'; } run_sub(); sub run_sub { print "Running\n";} sub run_sub { print "Ran\n";} if ($debug > 3) {print "DEBUG: blah, blah, ...\n";}

    Have tried a few modifications, but none eliminated the 'redefine' warnings when ($debug > 2).

      Have tried a few modifications, but none eliminated the 'redefine' warnings when ($debug > 2).

      That's because it has a lexical scope, and the scope in your code is the containing block. This ugly alternative works:

      BEGIN { warnings->unimport( 'redefine' ) if $debug > 2 }

      Improve your skills with Modern Perl: the free book.

        It's not ugly - it's Perl. Thank you. Again, great explanations folks - your advice is very much appreciated.