in reply to Re^2: What is the scope of BEGIN? Or... when does it "begin?"
in thread What is the scope of BEGIN? Or... when does it "begin?"

I've read every message in this thread and the referenced thread. I've yet to see any code that would behave differently than I expect. However, you're still referring to behavior that "seems odd". Can you post the precise code that puzzles you, so we can follow along better than just some handwaving?

Keep in mind that environment variables are not yet set at the time of BEGIN, which also means they aren't set at the time of any use. If you're setting variables based on that, you'll be very confused.

-- Randal L. Schwartz, Perl hacker
Be sure to read my standard disclaimer if this is a reply.


update: oops, misremembering about %ENV not being set at compile time. I wonder what it is that I was doing that made me misremember that.
  • Comment on Re^3: What is the scope of BEGIN? Or... when does it "begin?"

Replies are listed 'Best First'.
Re^4: What is the scope of BEGIN? Or... when does it "begin?"
by ysth (Canon) on May 06, 2005 at 16:15 UTC
    Keep in mind that environment variables are not yet set at the time of BEGIN
    I'm not sure what you mean by that.
    $ perl -we'BEGIN{print $ENV{MANPATH}}' /usr/man:/usr/local/man:/usr/share/man:/usr/autotool/devel/man:
Re^4: What is the scope of BEGIN? Or... when does it "begin?"
by argv (Pilgrim) on May 06, 2005 at 17:17 UTC
    Here's code that illustrates the question. I start with "Foo.pm":

    # Foo.pm my $shell = $ENV{'SHELL'} || ""; BEGIN { if ( $ENV{'SHELL'}) { print "\$ENV{'SHELL'} is $ENV{'SHELL'}...\n"; } else { print "\$ENV{'SHELL'} is not set...\n"; } if ( $shell ) { print "\$shell is $shell...\n"; } else { print "\$shell is not set...\n"; } } 1;

    Now, the perl script, "foo" has nothing but:

    #!/usr/bin/perl use Foo; print "done.\n";

    Running the program should be self-explanitory. The question is: if "use" is an implicit BEGIN, and there is no precedence to the orders of the BEGIN blocks, then why isn't "$shell" set outside of the BEGIN block on Foo.pm?

    And, as far as Randall's comment about environment variables not set at the time of BEGIN, then what explains the behavior of this sample program?

      Perl scripts are read by perl one line at a time and the code is compiled as it is read. Right after the '}' that ends a BEGIN block is read (compiled), the code inside the block is run. require causes a different file to be read. use does a require inside of a BEGIN block. After the last line of code of a Perl file is read (either the main script or a required module), the code in that file starts running from the top. Code in subroutines isn't run until the subroutine is called, of course. my $var= EXPR; declares $var when that statement is compiled but evaluates EXPR and assigns it to $var only when that statement is run.

      That is all you need to know to trace the execution order of Perl code (things like END, INIT blocks, and string-eval require additional specific knowledge, of course).

      Each statement has it's own specific "compile time" and zero or more specific "run times". People often talk about "run-time" or "compile-time" actions in broad-sounding terms and even sometimes make the mistake of talking about some global "run time" or global "compile time". But each statement has its own time when it gets compiled and own time(s) when it gets run. They can interleave in interesting ways because of things like BEGIN, use, require, and eval.

      So just follow the order in which Perl reads the lines and the order things get done is quite clear.

      For "use Foo;", the order is:

      Compile: use Foo; Compile: BEGIN { require Foo; import Foo; } Run: require Foo; (starts compiling Foo.pm) Compile: my $shell = $ENV{'SHELL'} || ""; (my $shell; gets declared) Compile: BEGIN { ... } Run: Code from above BEGIN block ($shell is declared but uninitialized here) Compile: 1; (Foo.pm fully compiled, start running it) Run: my $shell = $ENV{'SHELL'} || ""; Run: 1; (require Foo; returns) Run: import Foo; ...

      Clearer?

      - tye        

        Yes, clearer, but there are two things:

        1) There was a statement by someone before that BEGINs have no order in their precedence or execution, and I think your explanation shows that there is. Their order and precedence goes in sequence to a very well-defined list (the one you enumerated). Is that not true?

        2) you didn't address the open issue regarding when $ENV has value(s). Randall says they don't at BEGIN time, but it seems they do. What about this?