Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Perl Misc (http://www.velocityreviews.com/forums/f67-perl-misc.html)
-   -   Should I use BEGIN, CHECK, or INIT? (http://www.velocityreviews.com/forums/t888774-should-i-use-begin-check-or-init.html)

J. Romano 10-28-2004 02:32 AM

Should I use BEGIN, CHECK, or INIT?
 
Greetings,

I have a couple of questions and I would like to know the opinions
of the Perl community.

I while ago, I wrote a Perl module which is now practically
finished. Its exact contents aren't important for my questions,
except for the fact that it is a package and its functions are called
like:

use MyPackage;
MyPackage::init();
MyPackage::f1();
MyPackage::f2($var1, $var2);

The first function that must be called is an initialization
function (MyPackage::init()). It must be called before any other
function in the package and should only be called once. This fact is
well-documented in the perldoc documentation, so any Perl programmer
who bothers to check this module's documentation should be aware of
it.

However, recently I've been thinking: If the init() function has
to be called before any other function and should only be called once,
why not put the initialization call in a BEGIN block inside the module
itself? That way, the programmer who uses my module doesn't even have
to call the init() function; it will be done automatically at the "use
MyPackage;" statement.

My first question is: Is putting the initialization function
inside a BEGIN (or CHECK or INIT) block a good idea, or is there some
pontential problem that I'm not aware of? If the initialization
function fails, I want it to stop the program from running at all. Of
course, if I do put the init() function in a BEGIN block, I'll remove
all mention of it from the perldoc so the programmer won't be tempted
to use it.

And my second question: If it is a good idea to automatically call
the init() function for the programmer, should I:

a) put the init() statement in a BEGIN block
b) put the init() statement in a CHECK block
c) put the init() statement in an INIT block
d) put the init() statement as the last statement executed
in the module
or
e) it's not a good idea, so just let the programmer who uses
my module call it in his/her own code

The only difference I see between BEGIN, CHECK, and INIT (besides
the facts that BEGIN statments happen before CHECK statements which
happen before INIT statements and that CHECK statements happen in
"First In, Last Out" order) is that if I put the init() function in a
BEGIN or CHECK block and the init() function fails, then it is
discovered at compile time. In other words, if the init() function
fails, then the statement:

perl -c myscript.pl

will fail as well, as long as the init() function call is placed
inside a BEGIN block or a CHECK block.

This sounds appealing in that "use MyPackage;" will fail if the
init() function fails, bringing it right away to the attention of the
programmer. However, it's possible that I might not see an obvious
problem with this approach, and so I would like any advice or comments
from anyone who might have had experience with something similar.

To sum up my questions: Should I put the init() call in a BEGIN,
CHECK, or INIT block, or should I just let the programmer who uses my
module do it automatically (and document it thoroughly in the
perldoc)?

Thanks in advance for any advice.

-- Jean-Luc

Tassilo v. Parseval 10-28-2004 04:53 AM

Re: Should I use BEGIN, CHECK, or INIT?
 
Also sprach J. Romano:

> I while ago, I wrote a Perl module which is now practically
> finished. Its exact contents aren't important for my questions,
> except for the fact that it is a package and its functions are called
> like:


[...]

> The first function that must be called is an initialization
> function (MyPackage::init()). It must be called before any other
> function in the package and should only be called once. This fact is
> well-documented in the perldoc documentation, so any Perl programmer
> who bothers to check this module's documentation should be aware of
> it.
>
> However, recently I've been thinking: If the init() function has
> to be called before any other function and should only be called once,
> why not put the initialization call in a BEGIN block inside the module
> itself? That way, the programmer who uses my module doesn't even have
> to call the init() function; it will be done automatically at the "use
> MyPackage;" statement.
>
> My first question is: Is putting the initialization function
> inside a BEGIN (or CHECK or INIT) block a good idea, or is there some
> pontential problem that I'm not aware of? If the initialization
> function fails, I want it to stop the program from running at all. Of
> course, if I do put the init() function in a BEGIN block, I'll remove
> all mention of it from the perldoc so the programmer won't be tempted
> to use it.


That appears to be good idea.

> And my second question: If it is a good idea to automatically call
> the init() function for the programmer, should I:
>
> a) put the init() statement in a BEGIN block
> b) put the init() statement in a CHECK block
> c) put the init() statement in an INIT block
> d) put the init() statement as the last statement executed
> in the module


There's really not much difference between any of those alternatives.
Putting it in a BEGIN block means that it is executed very early, even
before the rest of the module is compiled. Since the module cannot be
used without successfully calling YourModule::init() anyway, there is no
need to finish compilation of it so it doesn't harm to die very early.

> or
> e) it's not a good idea, so just let the programmer who uses
> my module call it in his/her own code


You should at least give him the opportunity to call it manually even
when it usually must not be done. I had a problem lately with one of my
modules where I called an init function in a BOOT-section of the XS
portion [which is roughly equivalent to d) in the above list]. I
received reports that the module didn't work in processes that had been
forked off. And indeed, it turned out that the underlying C-library
required this initialization to happen in each process.

So call init() in a BEGIN block but also document that it must be called
manually when using the module's functionality in child processes.

Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus}) !JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexi ixesixeseg;y~\n~~dddd;eval

Peter Hickman 10-28-2004 08:22 AM

Re: Should I use BEGIN, CHECK, or INIT?
 
J. Romano wrote:
> And my second question: If it is a good idea to automatically call
> the init() function for the programmer, should I:
>
> a) put the init() statement in a BEGIN block
> b) put the init() statement in a CHECK block
> c) put the init() statement in an INIT block
> d) put the init() statement as the last statement executed
> in the module
> or
> e) it's not a good idea, so just let the programmer who uses
> my module call it in his/her own code


I would put it in the BEGIN block and if I was really worried about the init()
function being called only once I would make that a closure.


BEGIN { init(); }

{
my $called = 0;

sub init {
unless( $called ) {
print "Called init for the first time\n";
$called = 1;
} else {
print "Init has already been called\n";
}
}
}

I would not put it in the CHECK block in case there were any side effects of
calling it such as opening database connections, files or the like. As, I
believe, that CHECK is called when you do...

perl -c Module.pm

where as BEGIN is not.

I think, can anyone confirm this. I am only on my first cup to tea.

Anno Siegel 10-28-2004 09:48 AM

Re: Should I use BEGIN, CHECK, or INIT?
 
J. Romano <jl_post@hotmail.com> wrote in comp.lang.perl.misc:
> Greetings,
>
> I have a couple of questions and I would like to know the opinions
> of the Perl community.
>
> I while ago, I wrote a Perl module which is now practically
> finished. Its exact contents aren't important for my questions,
> except for the fact that it is a package and its functions are called
> like:
>
> use MyPackage;
> MyPackage::init();
> MyPackage::f1();
> MyPackage::f2($var1, $var2);


[...]

> And my second question: If it is a good idea to automatically call
> the init() function for the programmer, should I:
>
> a) put the init() statement in a BEGIN block
> b) put the init() statement in a CHECK block
> c) put the init() statement in an INIT block
> d) put the init() statement as the last statement executed
> in the module
> or
> e) it's not a good idea, so just let the programmer who uses
> my module call it in his/her own code


I have little to add to Tassilo's thorough discussion of the issue,
except still another alternative:

f) rename the init() function as import() (or call it from
the import() function)

That (import()) will be called after the last executable statement
of your module, but before "use" returns to the caller, so it is
basically equivalent to d). The difference is that the user has
the choice to suppress the call to import() and call it on their
own.

> The only difference I see between BEGIN, CHECK, and INIT (besides
> the facts that BEGIN statments happen before CHECK statements which
> happen before INIT statements and that CHECK statements happen in


Another difference is that BEGIN and CHECK are executed when the
module in question is loaded. INIT (and END) are collected and
not executed before all compile-time activity is done, so if more
modules are loaded, INIT only runs after that has happened.

Anno

Ben Morrow 10-28-2004 02:48 PM

Re: Should I use BEGIN, CHECK, or INIT?
 

Quoth "Tassilo v. Parseval" <tassilo.von.parseval@rwth-aachen.de>:
> Also sprach J. Romano:
>
> > And my second question: If it is a good idea to automatically call
> > the init() function for the programmer, should I:
> >
> > a) put the init() statement in a BEGIN block
> > b) put the init() statement in a CHECK block


You should not put things in CHECK blocks, in general. They are hooks
for the (unimplemented) perl compiler.

> > c) put the init() statement in an INIT block


I would say here is best, but it really makes no difference. Putting
init stuff in init blocks is necessary for any form of perl compiler to
work (including things I have tried to do in the past to make PAR's
module-detection mechanism more reliable in the face of modules which
use other modules for you, such as 'if' and 'all'); however, this
convention is so universally ignored that there is little point trying
to follow it.

> > or
> > e) it's not a good idea, so just let the programmer who uses
> > my module call it in his/her own code

>
> You should at least give him the opportunity to call it manually even
> when it usually must not be done.


As you're going to do this, I would recommend calling it from ->import.
Thn the user can choose (if necessary) not to call it with

use Module ();

and then call it later when necessary.

Ben

--
For far more marvellous is the truth than any artists of the past imagined!
Why do the poets of the present not speak of it? What men are poets who can
speak of Jupiter if he were like a man, but if he is an immense spinning
sphere of methane and ammonia must be silent? [Feynmann] ben@morrow.me.uk

Brian McCauley 10-28-2004 05:01 PM

Re: Should I use BEGIN, CHECK, or INIT?
 


Douglas Hunter wrote:

> Peter Hickman wrote:
>
>> I would not put it in the CHECK block in case there were any side
>> effects of calling it such as opening database connections, files or
>> the like. As, I believe, that CHECK is called when you do...
>>
>> perl -c Module.pm
>>
>> where as BEGIN is not.
>>

>
> dug@slurp:~/scratch$ cat A.pm
> package A;
>
> BEGIN { warn "begin" }
> CHECK { warn "check" }
> INIT { warn "init" }
> END { warn "end" }
>
> 1;


For more complete view of things...

bam@wcl-l:~/tmp> cat A1.pm
package A1;
sub import { warn "import" };
BEGIN { warn "begin" }
CHECK { warn "check" }
INIT { warn "init" }
END { warn "end" }
warn "body";
1;

bam@wcl-l:~/tmp> cat A2.pm
package A2;
sub import { warn "import" };
BEGIN { warn "begin" }
CHECK { warn "check" }
INIT { warn "init" }
END { warn "end" }
warn "body";
1;

bam@wcl-l:~/tmp> perl -ce 'use A1; use A1; use A2;'
begin at A1.pm line 3.
body at A1.pm line 7.
import at A1.pm line 2.
import at A1.pm line 2.
begin at A2.pm line 3.
body at A2.pm line 7.
import at A2.pm line 2.
check at A2.pm line 4.
check at A1.pm line 4.
-e syntax OK

bam@wcl-l:~/tmp> perl -e 'use A1; use A1; use A2;'
begin at A1.pm line 3.
body at A1.pm line 7.
import at A1.pm line 2.
import at A1.pm line 2.
begin at A2.pm line 3.
body at A2.pm line 7.
import at A2.pm line 2.
check at A2.pm line 4.
check at A1.pm line 4.
init at A1.pm line 5.
init at A2.pm line 5.
end at A2.pm line 6.
end at A1.pm line 6.

bam@wcl-l:~/tmp> perl -e 'require A1; require A1; require A2;'
begin at A1.pm line 3.
body at A1.pm line 7.
begin at A2.pm line 3.
body at A2.pm line 7.
end at A2.pm line 6.
end at A1.pm line 6.

My view is that initialisaton code that must be run once and once only
when the module is loaded and which doesn't connect to any external
resource is best called in the module body unless there's a specific
reason to put it elsewhere.

> > I think, can anyone confirm this. I am only on my first cup to tea.

>
> Whereas I have the luxury of being well into my second cup of coffee
> {grin}.


And I'm dangerously close to an overdose.


Brian McCauley 10-28-2004 05:21 PM

Re: Should I use BEGIN, CHECK, or INIT?
 


Anno Siegel wrote:

> J. Romano <jl_post@hotmail.com> wrote in comp.lang.perl.misc:
>
>>Greetings,
>>
>> I have a couple of questions and I would like to know the opinions
>>of the Perl community.
>>
>> I while ago, I wrote a Perl module which is now practically
>>finished. Its exact contents aren't important for my questions,
>>except for the fact that it is a package and its functions are called
>>like:
>>
>> use MyPackage;
>> MyPackage::init();
>> MyPackage::f1();
>> MyPackage::f2($var1, $var2);

>
>
> [...]
>
>
>> And my second question: If it is a good idea to automatically call
>>the init() function for the programmer, should I:
>>
>> a) put the init() statement in a BEGIN block
>> b) put the init() statement in a CHECK block
>> c) put the init() statement in an INIT block
>> d) put the init() statement as the last statement executed
>> in the module
>> or
>> e) it's not a good idea, so just let the programmer who uses
>> my module call it in his/her own code

>
>
> I have little to add to Tassilo's thorough discussion of the issue,
> except still another alternative:
>
> f) rename the init() function as import() (or call it from
> the import() function)
>
> That (import()) will be called after the last executable statement
> of your module, but before "use" returns to the caller, so it is
> basically equivalent to d). The difference is that the user has
> the choice to suppress the call to import() and call it on their
> own.
>
>
>> The only difference I see between BEGIN, CHECK, and INIT (besides
>>the facts that BEGIN statments happen before CHECK statements which
>>happen before INIT statements and that CHECK statements happen in

>
>
> Another difference is that BEGIN and CHECK are executed when the
> module in question is loaded. INIT (and END) are collected and
> not executed before all compile-time activity is done, so if more
> modules are loaded, INIT only runs after that has happened.
>
> Anno



Brian McCauley 10-28-2004 05:22 PM

Re: Should I use BEGIN, CHECK, or INIT?
 


Brian McCauley wrote:

>
>
> Anno Siegel wrote:


[snip most of Anno's message ]

>> I have little to add to Tassilo's thorough discussion of the issue,
>> except still another alternative:
>>
>> f) rename the init() function as import() (or call it from
>> the import() function)
>>
>> That (import()) will be called after the last executable statement
>> of your module, but before "use" returns to the caller, so it is
>> basically equivalent to d). The difference is that the user has
>> the choice to suppress the call to import() and call it on their
>> own.


import() is called each time the module use use()d. It is therefore
inappropriate for initialisation that should happen once regardless of
how many times the module is used.


Ben Morrow 10-28-2004 09:14 PM

Re: Should I use BEGIN, CHECK, or INIT?
 

Quoth abigail@abigail.nl:
> It's not entirely clear to me when (or if) an INIT in a module is run.
> Is that just before runtime of the main program, or just before runtime
> of the module?


All INIT blocks parsed during the main script's compile time (the call
to perl_parse) are queued, and are run in FIFO order at the beginning of
perl_run. INIT blocks parsed after perl_run has started are never run.
Thus, if a used module defines an init block, it will be run at the
beginning of the execution of the main script (well after the use
statement has finished); if a required one defines one it will never be
run.

Ben

--
Heracles: Vulture! Here's a titbit for you / A few dried molecules of the gall
From the liver of a friend of yours. / Excuse the arrow but I have no spoon.
(Ted Hughes, [ Heracles shoots Vulture with arrow. Vulture bursts into ]
/Alcestis/) [ flame, and falls out of sight. ] ben@morrow.me.uk

Anno Siegel 10-28-2004 09:58 PM

Re: Should I use BEGIN, CHECK, or INIT?
 
Abigail <abigail@abigail.nl> wrote in comp.lang.perl.misc:
> Brian McCauley (nobull@mail.com) wrote on MMMMLXXVI September MCMXCIII in
> <URL:news:clr9kl$ia4$4@sun3.bham.ac.uk>:
> --
> --
> -- Brian McCauley wrote:
> --
> -- >
> -- >
> -- > Anno Siegel wrote:
> --
> -- [snip most of Anno's message ]
> --
> -- >> I have little to add to Tassilo's thorough discussion of the issue,
> -- >> except still another alternative:
> -- >>
> -- >> f) rename the init() function as import() (or call it from
> -- >> the import() function)
> -- >>
> -- >> That (import()) will be called after the last executable statement
> -- >> of your module, but before "use" returns to the caller, so it is
> -- >> basically equivalent to d). The difference is that the user has
> -- >> the choice to suppress the call to import() and call it on their
> -- >> own.
> --
> -- import() is called each time the module use use()d. It is therefore
> -- inappropriate for initialisation that should happen once regardless of
> -- how many times the module is used.
>
>
> my $ping_a_pong;
> sub import {
> $ping_a_pong ++ or do {
> ... initialization code ...
> };
> }


Either that, or the initialization is prepared to be run more than once,
perhaps with different parameters, by different callers.

> I'd hesitate to use INIT in a module. From "man perlmod":
>
> "INIT" blocks are run just before the Perl runtime begins
> execution, in "first in, first out" (FIFO) order. For
> example, the code generators documented in perlcc make use
> of "INIT" blocks to initialize and resolve pointers to
> XSUBs.
>
> It's not entirely clear to me when (or if) an INIT in a module is run.
> Is that just before runtime of the main program, or just before runtime
> of the module?


I had always "known" that INIT runs before the first executable statement
of the main program. Could be that I blithely assumed, but the assumption
is supported by the actual behavior of programs.

It would be a time to see which other modules are loaded and what
they are up to. Modules that modify the behavior of other modules,
or of Perl as a whole, may have business that is best done at INIT
time.

> However, if I need to initialize something in a module, I wouldn't use
> BEGIN, INIT, or CHECK, nor would I use import() or require an init()
> function to be called.
>
> I'd either put the initialization code in the main body of the module,
> or just the call to init(). After all, a module, whether required or used,
> *is* executed. Once. Right after it was compiled. Which sounds exactly
> what the OP wants. (Sure, it would run multiple times if people use
> 'do Module;', or much with '%INC'. But that's their problem.)


That is, of course, the natural thing to do when there is no reason
to delay initialization. Sometimes you want to adapt to a given
situation and may want to do that a late as possible. For example,
sometimes class initialization is done the first time ->new is called,
even later than INIT.

Anno


All times are GMT. The time now is 02:47 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.