views:

230

answers:

3

I know what they all do, but have never found myself in a situation where I've needed any of them. I've used BEGIN blocks on many occasions and ENDs 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.

+7  A: 

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)

DVK
Also, I never tried it but these *might* be plausibly leveraged for some interesting mocking approaches - if someone has an idea, feel free to expand on this possibility as a separate answer.
DVK
+5  A: 

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.

mobrule
Now I remember why I didn't want to do `require Module;Module->import(@stuff)`. It was because I already had a suite of test scripts I wanted to be able to debug, and I didn't want to edit the `use Module` statement in every file.
mobrule
You don't need to go through those contortions to debug compile-time code. Just place $DB::single=1 anywhere in your source and the debugger will stop at that point, no matter which phase of processing the program is in. (see http://perldoc.perl.org/perldebug.html#Debugging-compile-time-statements)
Brian Phillips
Thanks Brian! That's good to know.
mobrule
+4  A: 

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 in BEGIN blocks and import 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.

Axeman
Axeman - for the initialization, could you please clarify what were your usages where INIT block was providing something special not achievable by simply placing init code at the start of the regular program? Is it just for visualization/ease of maintenance?
DVK
@DVK: I've used INIT blocks in modules to perform class initialization; the user shouldn't have to know about that sort of thing. Unfortunately, PAR::Packer has problems with scheduled blocks (INIT and CHECK in particular) so this doesn't work for modules that might be distributed that way. I usually end up ripping out the INIT block in favor of an `initialize()` sub that gets called the first time the constructor is invoked.
Michael Carman