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

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

I'm wondering if other monks have been bitten by this. FYI, Acme::PERLANCAR::DumpImportArgs is just a supersimple module to dump its import() arguments.

% perl -wE'BEGIN { $vars{k} = "v1"; use Acme::PERLANCAR::DumpImportArgs %vars }'
Import arguments: "Acme::PERLANCAR::DumpImportArgs"

% perl -wE'BEGIN { $vars{k} = "v1" } use Acme::PERLANCAR::DumpImportArgs %vars;'
Import arguments: ("Acme::PERLANCAR::DumpImportArgs", "k", "v1")

No warnings.

Also, I wanted %vars to be lexical.

  • Comment on Assignment and use statement in the same BEGIN block

Replies are listed 'Best First'.
Re: Assignment and use statement in the same BEGIN block
by choroba (Bishop) on Jan 31, 2019 at 07:39 UTC
    Each use statement is executed at the moment it's been parsed. The same applies to a BEGIN block. my has two parts - the declaration of the variable happens immediately at compile time, the assignment happens later at run time. Therefore, in the first case, the dumping happens before the BEGIN block has been fully parsed, which means its (the BEGIN block's) code hasn't been run yet.

    To make the variable lexical, specify

    my %vars;
    before the BEGIN block.

    Update: You probably wanted something like

    { my %vars; BEGIN { $vars{k} = 'v'; } use Acme::PERLANCAR::DumpImportArgs %vars; }

    Update 2: Explanation of two parts of my.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Assignment and use statement in the same BEGIN block
by Discipulus (Abbot) on Jan 31, 2019 at 08:03 UTC
    Hello my friend perlancar,

    you already had the perfect, concise answer by choroba, but let me expand something that can be useful.

     use Module;   <=>  BEGIN { require Module; Module->import( LIST ); }

    ikegami on SO explains it in this way:

    # script.pl use Foo; my $foo = Foo->new(); $foo->do(); # does: 1.Compile script.pl 1.Compile use Foo; 2.Execute require Foo; 1.Compile Foo.pm 1. ... 2.Execute Foo.pm 1. ... 3.Execute import Foo; 4.Compile my $foo = Foo->new(); 5.Compile $foo->do(); 2.Execute script.pl 1.Execute my $foo = Foo->new(); 2.Execute $foo->do();

    Wich unveils the compiletime/runtime dicotomy.

    Also very interesting read is Re: RunTime & compile Time Doubt on Perl (many) and the document I always called twelve pillars of wisdom (but i do not remember if it was named this way..) as found in perlmod

    print "10. Ordinary code runs at runtime.\n"; END { print "16. So this is the end of the tale.\n" } INIT { print " 7. INIT blocks run FIFO just before runtime.\n" } UNITCHECK { print " 4. And therefore before any CHECK blocks +.\n" } CHECK { print " 6. So this is the sixth line.\n" } print "11. It runs in order, of course.\n"; BEGIN { print " 1. BEGIN blocks run FIFO during compilation.\n" } END { print "15. Read perlmod for the rest of the story.\n" } CHECK { print " 5. CHECK blocks run LIFO after all compilation.\n" } INIT { print " 8. Run this again, using Perl's -c switch.\n" } print "12. This is anti-obfuscated code.\n"; END { print "14. END blocks run LIFO at quitting time.\n" } BEGIN { print " 2. So this line comes out second.\n" } UNITCHECK { print " 3. UNITCHECK blocks run LIFO after each file is +compiled.\n" } INIT { print " 9. You'll see the difference right away.\n" } print "13. It only _looks_ like it should be confusing.\n" +;

    other interesting reads are at your disposal in my bibliotheca

    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: Assignment and use statement in the same BEGIN block
by tobyink (Abbot) on Jan 31, 2019 at 09:06 UTC

    A use within a BEGIN is effectively a BEGIN within a BEGIN.

    This should work:

    perl -wE'BEGIN { $vars{k} = "v1"; require Acme::PERLANCAR::DumpImportA +rgs; import Acme::PERLANCAR::DumpImportArgs %vars }'

      Thanks choroba, my friend Discipulus, and tobyink for all the useful explanation.

      Toby's clicks the most to me. And this snippet makes things very clear to me: BEGIN { say 1; BEGIN { say 2 } } printing 2 before 1. In other words, you ain't finish BEGIN'ing until you end (close) it. Sigh. And the specialness of the use statement again standing in my way.

        > you ain't finish BEGIN'ing until you end (close) it

        (this is life..)

        indeed! and I never realized they can be nested!

        perl -e "$}.=qq(BEGIN{print qq($_);)for(q(,rekcaH lreP rehtonA tsuJ)=~/./g);$}.=q(})x25;eval$}"

        L*

        update

        removed and published separately as obfu

        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.