Q on BEGIN and INIT

J

J Krugman

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?

TIA!

jill

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

Anno Siegel

J Krugman said:
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.

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:
blocks don't work in mod_perl, for the same reason [this doesn't]:

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

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.

Anno
 
J

J Krugman

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". :)

jill
 
J

Joe Smith

J said:
? 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

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.
http://groups-beta.google.com/group/comp.lang.perl.misc/msg/21bf0b72893b2f16

Alex said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top