http://qs1969.pair.com?node_id=404799


in reply to Re: use and require inside subs
in thread use and require inside subs

I thought I knew this, but why do I put my use statements inside if/then if it happens at compile time?
use warnings; use strict; my $config; if ($^O eq 'MSWin32') { use Win32::TieRegistry( Delimiter=>"/", ArrayValues=>0 ); # load $config from registry } else { # else load $config from flat files }
Too tired to think for myself tonight.

Replies are listed 'Best First'.
Re^3: use and require inside subs
by tachyon (Chancellor) on Nov 03, 2004 at 01:00 UTC
      Even more convincing is to put the print statement before the if statement.
      print "$_\n" for keys %INC; if (0) { print "This block is happening!\n"; use Win32; }

      --
      [ e d @ h a l l e y . c c ]

      hehe, so maybe I don't run that cross-platform code on other platforms recently :-) I'll have to dig it up and see what I actually did now.

      Cheers
Re^3: use and require inside subs
by Ytrew (Pilgrim) on Nov 03, 2004 at 04:15 UTC
    I thought I knew this, but why do I put my use statements inside if/then if it happens at compile time?

    As Tachyon points out, you shouldn't. Or at least, run-time statements won't get executed at compile time, so your code won't do what you want.

    Remember, the use() command has an implicit BEGIN block around it, which forces the statements to be executed at compile time. The statement:

    use module;

    is like writing:

    BEGIN { require "module.pm;" module::import(); }

    So, you have two choices. You can make all the decisions about which code to include at run-time, and use "require" statements.

    As ysth points out, something like the following doesn't actually work, though I initially thought it did.

    use warnings; use strict; my $config; BEGIN { if ($^O eq 'MSWin32') { use Win32::TieRegistry( Delimiter=>"/", ArrayValues=>0 ); # load $config from registry } else { # else load $config from flat files } } # end system specific compile time code

    Since BEGIN blocks and use statements both now happen at "compile time", the above code should work, right? Nope. There's a specifically defined order to how BEGIN blocks execute, and it's not what I had assumed it was.

    Upon a careful reading of the perl module documentation page, (type "perldoc perlmod" to read it), I think I understand how it all works. Comments and corrections are appreciated.

    According to the documentation: A "BEGIN" code block is executed as soon as possible, that is, the moment it is completely defined.

    The documentation doesn't say exactly what "completely defined" means, but I took it to mean when the end of the BEGIN block is reached, when reading sequentially through the code. This implies that code like this:

    BEGIN { print "-one-"; BEGIN { print "-two-"; BEGIN { print "-three-; } # end of block that prints "-three-" } # end of block that prints "-two-" } # end of block that prints "-one-"
    should print "-three-two-one", because the end of the block that prints "-three-" is encountered first, then "-two-", then "-one-". This is what happens when I run it, which implies I'm at least close to right.

    It also means that when you write a BEGIN block with a "use" statement inside it, the end of the use statement gets reached before the end of the BEGIN block. Since a use statment is really an implied BEGIN block, this means it executes first, before the BEGIN block gets a chance to do anything.

    Sorry for any confusion I caused. :-( --
    Ytreq Q. Uiop

      BEGIN { if ($^O eq 'MSWin32') { use Win32::TieRegistry( Delimiter=>"/", ArrayValues=>0 ); # load $config from registry } else { # else load $config from flat files } } # end system specific compile time code
      I think you mean
      require Win32::TieRegistry; Win32::TieRegistry::->import(Delimiter=>"/", ArrayValues=>0 );
      since the way you have it, perl will attempt to use that module even not on Win32.

      Another way:

      use if $^O eq 'MSWin32', "Win32::TieRegistry", Delimiter=>"/", ArrayValues=>0;
      if you have if.
      But how do you know that, its not like this is documented somewhere?
        Really? Tried perldoc -f use? Second paragraph?