Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re^7: Perl Modules -- abstraction and interfaces: exporter and @ISA

by haukex (Archbishop)
on Jul 11, 2017 at 19:25 UTC ( [id://1194858]=note: print w/replies, xml ) Need Help??


in reply to Re^6: Perl Modules -- abstraction and interfaces: exporter and @ISA
in thread Perl Modules

is this "good practice" - i mean the bit before the first sub?

I would answer this with "no". As you said, it might work, but there are two main reasons I would recommend against it.

First a practical point: usually, when you write a module like that, you'd be loading it with use. However, as documented in use, that code gets run in a BEGIN block, that is, while the calling code is still being complied. For some code, it will still work, but on the other hand you may get some unexpected effects (e.g. this thread). Also, modules might not yet be loaded and/or initialized depending on the order of the use statements in the calling code! (Even if you use require to load modules at runtime instead of compile time, note that this will lead to other possibly unexpected effects, like the code in that module still being executed only once, or you having to use parentheses on all your subroutine calls imported from that module.) This is why modules that are intended to be used usually limit themselves to declarations of subs and package variables (Update: and often the exporting of those subs into the caller's namespace, e.g. Exporter), and if they do have initialization code, it is limited to things that are internal to that module without externally visible side effects. (Update 2: Note I'm ignoring more complicated things like custom pragmas here, which are also just special kinds of modules.)

Second, something to do more with convention: When I load a module with use, I don't expect that call to have any side effects other than loading that module, but the code you showed not only prints something, it may even kill my whole program with exit!

So what can you do instead? If you want to write a module that is intended to be loaded with use, then it's easiest when it only contains sub definitions and perhaps declarations of package variables (our). If it does execute code on loading, then it should only be for its internal initialization, i.e. it shouldn't have any side effects visible to outside code, and it needs to consider that it is being executed in a BEGIN block, as I explained above (Update: i.e., I wouldn't mess with cookies or CGI params that that point yet). If you want to include initialization code with effects visible to the outside code, then for example, put it in a sub init that the user has to explicitly call.

Another approach, which I would consider to be less elegant, would be to use do to explicitly execute another Perl file. Unlike require, that Perl file will be executed every time you call do instead of only once, so it's more like calling a sub than loading a module. However, in that case it's not necessarily the best place to put subs etc., so you'd have to consider splitting the code you showed into two parts. (So as you can tell, it's probably easier to just put the init code in a sub init instead.)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1194858]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (4)
As of 2024-04-20 00:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found