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

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

Or are they? I'm trying to write a module that uses bytes.pm only if it was requested in the import list, like - use module qw(LegacyEncoding and other options);

The problem is that if I use if, bytes will only be scoped to the if block. And anyway if I manage to avoid that (like with $legacy and use bytes) it will still be scped to the import sub.

Any way around it?
Thanks.

Replies are listed 'Best First'.
Re: if only blocks were avoidable...
by liz (Monsignor) on Sep 21, 2003 at 20:58 UTC
    The use bytes is basically setting $^H at compile time.

    According to that documentation, you should be able to do:

    BEGIN { require bytes; bytes->import if $condition }
    inside the block where you want the use bytes to be conditionally set. Of course, if you don't put it in a block, the file in which the source sits, will be your scope.

    This seems the right thing according to the docs and seems to work with stricture:

    $foo = $a; BEGIN { require strict; strict->import if 1 } $foo = $a; __END__ Variable "$foo" is not imported at x line 3. Global symbol "$foo" requires explicit package name at x line 3. x had compilation errors.
    If the import is not done, this runs without any errors:
    $foo = $a; BEGIN { require strict; strict->import if 0 } $foo = $a; __END__

    Hope this made sense and helps.

    Liz

      OK, it turns out that this isn't what I need, because if I use BEGIN, I can't use parameters passed to sub in order to decide on the condition. I can only use environment variables, perl variables and other stuff that already exists before anything happens.

      What I need is this:

      sub import { $_[1] eq 'StoneAge' and use bytes globally; #no such thing. }

      BEGIN can't achieve that.

        Ok, I guess I missed that particular point. Well, I think it is possible, but it's rather yucky and it suffers from the same problems that AutoLoader and the likes have. Basically, you compile your code in a two step process. First to compile the "import" routine. Then, when the import routine is called, the rest of the source is compiled Consider module Foo:
        package Foo; require bytes; # make sure the module is loaded without (un)import $bytes = 0; # flag: whether bytes should be enforced $evalled = 0; # flag: whether rest of source has been compiled sub import { unless ($evalled++) { # we haven't evalled the rest +before $bytes = ($_[1] eq "usebytes"); # should bytes be enforced? local $/; # enable slurp mode eval <DATA>; # compile rest of source (afte +r __DATA__) die $@ if $@; # die now if an error occurred } }; 1; # in order for require of Foo.pm to be + successful __DATA__ # actual source of module starts here BEGIN {bytes->import if $bytes} # activate bytes if flag set sub new { bless {},shift } # example routine
        Then, in an example program, you would do:
        use Foo 'usebytes'; # or something else to not use bytes my $foo = Foo->new;
        Hope this will help you in your quest.

        Liz

      So if I understand what you (and perlvar) say correctly, the BEGIN block is what's going to make my import globally scoped? If that's the case then I guess that's what I was looking for.
      Thanks.
        No. Wrapping an import call in a BEGIN block will make it happen at compile time.
Re: if only blocks were avoidable...
by jeffa (Bishop) on Sep 21, 2003 at 20:22 UTC
    Not quite sure if i am following you, but have you tried require instead? The "problem" with use is that no matter where it is, the module will be loaded. Consider this:
    if (0) { use CGI qw(:standard); } print header,"\n";
    Which does load CGI.pm and no compile error happens because there really is a header() method available. Try using require instead.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)