Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View

In Programming Perl, Third Edition, page 484, it says:

  INIT blocks are really just like BEGIN blocks, except they let
  the programmer distinguish construction that must happen at
  compile phase from construction that must happen at run phase.
  When you're running a script directly, that's not terribly
  important because the compiler gets invoked every time anyway;
  but when compilation is separate from execution, the distinction
  can be crucial. The compiler may only be invoked once, and the
  resulting executable may be invoked many times.

The last sentence suggests that if initialization code is stuck in
a BEGIN block for a program that is compiled once but run many
times, then the initialization will not be properly done except
for the very first execution.  The only common scenario I could
think of where this separation of compilation and execution would
happen is something like mod_perl, but then I found this in Practical
mod_perl by Bekman and Cholet:

  Perl calls [INIT and CHECK] blocks only during perl_parse( ),
  which mod_perl calls once at startup time. Therefore, ...INIT
  blocks don't work in mod_perl, for the same reason [this doesn't]:

  panic% perl -e 'eval qq(INIT  { print "ok\n" })'

So now I'm even more confused.  If Perl indeed calls INIT only
during perl_parse, then I don't see how the excerpt from PP can be
correct, since it seems farfetched that parsing of the program
could occur multiple times for a single compilation.

My two questions are: 1) notwithstanding the excerpt from PP, in
the case of a script intended to be run under mod_perl, would a
BEGIN block be the right way to take care of initialization code,
like this
    my $private; BEGIN { $private = 1 } sub foo {
      # use $private } }

?  And 2) what's a reasonably common, realistic scenario in which
compilation would happen once, execution many times, and the
distinction between BEGIN and INIT was meaningful in the sense
described by the PP excerpt above?



P.S. Is this the right forum for this question?

To  s&e^n]d  me  m~a}i]l  r%e*m?o\v[e  bit from my a|d)d:r{e:s]s.

Re: Q on BEGIN and INIT

Quoted text here. Click to load it

I don't find the above paragraph very enlightening either.

Having little experience with embedded Perl, and less with mod_perl,
I can't answer your specific questions concerning mod_perl.

This is how I model the behavior of BEGIN, INIT, END, and the rarely
used CHECK blocks:

First off, they are in many respects like subroutines.  The code is
not executed immediately, but stored away for later.  Also, they are
actual sub-blocks, you can return from them.  As with all subroutines,
compilation happens at, well, compile time.

They differ from subs in that there can be more than one of each.  All
INIT blocks are collected together, and so are END and CHECK blocks,
possibly BEGIN blocks too, though there it wouldn't matter.  INIT blocks
are collected in sequence, CHECK and END blocks in reverse sequence.
That may look weird, but in practice, if it matters at all, it tends
to make sense.

Also unlike real subs, you don't control when they are executed, but
Perl does.  BEGIN blocks are executed as soon as each one is compiled
(that's why is doesn't matter if they are collected somewhere).  CHECK
happens at the end of the compile phase, and INIT at the beginning of
run time, before the first statement of the main program is run.  That
means that CHECK immediately precedes INIT if both are present.
END is run when the program exits, though there are a few ways of
exiting a program without triggering END.

Let's look at the situation in Bekman and Cholet again:

Quoted text here. Click to load it

Indeed it doesn't work (and gives a warning to that effect).  That is
because when eval is called, the INIT block(s) (if any) have already
been run -- before the first executable statement.  Even if the block is
added to the INIT sequence by eval (I suppose it is), that has no effect.
A similar case is CHECK, which also cannot be added to at run time,
because it has already happened.  In contrast, adding an END block
in a run-time eval *has* an effect because it has yet to be executed.
A BEGIN block in string-eval also shows an effect, because each is
executed immediately.

In general, I wouldn't use an INIT block for general initializing
purposes.  Do it at normal run-time.  If you want the initializing code
near the code that uses it, there may be reason to do it in a BEGIN
block.  I'd use INIT if it were essential that all compilation and
module-loading has been done when it's called.  If not, it's just too
hard to say when it will run and when it won't.


Re: Q on BEGIN and INIT

Thanks!  Much appreciated.

I have come across a couple of passing mentions to the effect that
"INIT is broken", and I wonder if it has anything to do with the
quote from the mod_perl book.  I'm trying to get to the bottom of
it; I guess I'll have to start "wading through the deltas".  :)


To  s&e^n]d  me  m~a}i]l  r%e*m?o\v[e  bit from my a|d)d:r{e:s]s.

Re: Q on BEGIN and INIT

Quoted text here. Click to load it

What is appreciated?

Please quote some context in followups like everyone else does.

    Tad McClellan                          SGML consulting
    tadmc@augustmail.com                   Perl programming
    Fort Worth, Texas

Re: Q on BEGIN and INIT

J Krugman wrote:

Quoted text here. Click to load it

One blatant example is perlcc.
   Use perlcc to parse Perl creating C code, compile the C code
   creating and executable binary.  Run the binary multiple times.
    perldoc perlcc

Here's an example where INIT is executed only once, but the 'when'
of execution is significant.

Alex Lee wrote:
 > Does anyone know how I can silence this error from eval?

Simply redirect STDERR to a string in a BEGIN block.

linux% cat eval.pl
use strict; use warnings;
BEGIN { our $err = ''; close STDERR; open STDERR,'>',$err; }
CHECK { our $err;      print "Compile: $err" if $err;       }
INIT  { our $err = ''; close STDERR; open STDERR,'>',$err; }
END   { our $err;      print "Runtime: $err" if $err;       }

$_ = "abc" + 3;
$a = "xyz"; $b = 3; $_ = $a + $b;

linux% perl eval.pl
Compile: Argument "abc" isn't numeric in addition (+) at eval.pl line 7.
Runtime: Argument "xyz" isn't numeric in addition (+) at eval.pl line 8.

Note how it outputs 'Compile:' for one warning and 'Runtime:' for the other.

Site Timeline