What is the usefulness of CHECK, UNITCHECK and INIT blocks in Perl?
I know what they all do, but have never found myself in a 开发者_C百科situation where I've needed any of them. I've used BEGIN
blocks on many occasions and END
s once in a while. BEGIN
is especially useful when you need to tweak the environment before code gets run, and I've used END
in certain debugging situations to trap important state information for hard-to-track-down fatal errors.
Have you ever used CHECK
, UNITCHECK
or INIT
? If so, what for? And would a BEGIN
block not have sufficed for some reason?
The documentation for the blocks is on PerlDoc.
An interesting use of CHECK blocks is in "Advanced Perl programming" by Simon Cozens (O'Reilly) in Chapter 1, in "Doing things later with CHECK" section. He shows how to implement "final" java-like attribute
Also, Devel::Sub::Trace uses INIT blocks to incert traces (this info is from POD for Devel::Hook which is a module used for working with those named blocks)
I had a package import
function which would do some heavy duty processing and then make an eval
call. How do you debug something like that? The import function gets run when you use
the module, which takes place at compile time (like it was inside a BEGIN block). For some reason (I think it was because I needed to pass parameters to import
with heredoc notation, but it could have been something else), it wasn't good enough to say require Module; Module->import(@args)
.
So my workaround was to build the string for eval
in import
, and save it another variable.
Then I ran the eval
in an INIT
block. When you ran the debugger, the very first execution point was at the start of the INIT
block and I could use the debugger to step through the eval
statement.
Well BEGIN
blocks are run at compile time, as you know. So I keep it to code that needs to be run in order for my module to be imported.
I wrote a script wrapper, to do everything that was being done in boilerplate code that occurred in a couple hundred scripts.
- There were things I had to do to get the module reading to be
use
-d. That I ran inBEGIN
blocks andimport
sub. - But there was also all that boilerplate that initialized the services the script would use. Therefore, I ran these actions in the
INIT
blocks. - And ran necessary cleanup and exit code in the
END
blocks.
I think CHECK makes sense if you write modules with XS engines, but I have only used it a handful of times. One time I think it was to check out the suggestions in Intermediate Perl. And I can't offhand remember the other reasons.
But I use INIT
blocks when I feel that code is more part of the script, than setting up the module. In essence, I only do what is necessary during compile time.
perlmod explains those special blocks but indeed only BEGIN
and END
are commonly used.
They are just arrays of CVs, LIFO or FIFO.
Those blocks allow seperate timings when code is run, independent on the location in the source file. So you can keep code sections together, but they are executed at different times (PHASES
).
CHECK was added initially to run the compiler suite O (-MO=C...
) in a fixed order after module initialization (use package), and before the main program, to be able store the execution context there. This seperates compile-time (before) from run-time (after).
perl -c
stops after CHECK.
As I am the maintainer of the compilers, I use CHECK and -MO= extensively. My modules compile()
methods are called by O within a CHECK block. With Od (debugging O) I call the compile
method not in CHECK, but later in INIT, so the debugger steps into it. The debugger does not step into CHECK blocks per default, you have to force it with $DB::single=1
or use Od.
UNITCHECK was added later to fine-grain module compilation and loading, esp. .pmc
files.
I've never used that so far. It can also happen at run-time, so I might use it for type checks of run-time loaded modules.
INIT was then added to allow seperate class initialization.
I rarely use that, but it is handy.
精彩评论