Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

modules - do they get garbage collected? 2

Status
Not open for further replies.

1DMF

Programmer
Jan 18, 2005
8,795
0
0
GB
Hi,

I was wondering that if you place a 'use xxxx' within a sub block, does that module get dropped/ garbage collected when the sub exits?

Or does the perl interpreter first looks at all the code and load all modules it thinks it will need before execution.

So if you had a loop and within it you placed a 'use xxx' does it keep loading the module?

or does it load it the once and ignore all other calls to load / use it?

if you are going to use a module anywhere in your script might you as well place it at the top?



"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
Hi 1DMF,

interesting question. I tried the following:

#!/usr/bin/perl -w
use strict;

sub load_use {
use Data::Dumper;
print Data::Dumper->Dump([\%ENV]);
}

print Data::Dumper->Dump([\%ENV]);
load_use();
print Data::Dumper->Dump([\%ENV]);

and it worked fine. However the following fails on the first Dump before the load_use();

#!/usr/bin/perl -w
use strict;

sub load_use {

require Data::Dumper;
import Data::Dumper;
print Data::Dumper->Dump([\%ENV]);
}

print Data::Dumper->Dump([\%ENV]);
load_use();
print Data::Dumper->Dump([\%ENV]);

Removing the Dump before the load_use() works fine. Looking at the perldoc on use, it states that it's equivalent to the following:

BEGIN { require Data::Dumper; import Data::Dumper}

so it will always be executed as soon as it's defined, but the second method allows later loading of the module.

Once the module is loaded, it does not get unloaded. I looked and could not find anything related to the explicit unload of a module, although you can undef it's functions/methods.

Finally, the documentation for use suggests that it will not import the module more than once.

Does this answer your question?

Cheers,
Scott
 
Yes thanks, I discussed this on another techy forum and was told that 'use' loads it at compile time and 'require' loads it at runtime, also perl only loads modules once.

So it's good to have this confirmed.

I have now moved the 'use' statement to the top of the script instead of within the method block.

Thanks for your input, much appreciated.

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
One point I would make after playing around....

If you have two objects that both use the same module.

when you try to run a method in the second object, it fails to see the functions in the shared module.

I'm not sure but it could be because perl only loads the module the once and the first object gets it assigned to it or it is in its package scope.

As the second object didn't get the module loaded into its package scope the script falls over unable to find the method.

If i create two scripts that load and run each OOP module separate it works, if I try to use both in the same script the first runs but the second falls over, so I'm guessing this is the cause.



"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
I believe you are right on the money. It's the 'import' part of the 'use' that pulls the module into scope. The 'require' simply loads and parses it (checking to see if it's already loaded).

You should still be able to use the functions in the second module by explicity referencing them. i.e. for my previous examples I used Data::Dumper->Dump(). This works with only the 'require'.

Cheers,
Scott
 
You should still be able to use the functions in the second module by explicity referencing them

hmm that would make my script a bit ugly!

I'm happy to run them as separate jobs at 10 minute intervals, there will be 9 jobs in total, so the entire nights processing will run over 1 hour & 30 minutes!, but giving each script 10 minutes to finish is loads of time, so it's all comming together nicely!

Though going live with real data is going to be a butt clenching moment for sure!

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
hmm... I realised now I had not read you last post very well. What you are describing should be possible. Would you be happy to let me look at the scripts and see what is causing the problem in the second module?

Cheers,
Scott
 
ok - so I have dug around, but cannot find a way to PM you my contact details! :)

I'm probably missing something, but if you want to send me the script, you can e-mail me sdeaks at gmail.com

Cheers!
 
I can't provide the script as it is sensative and has non-disclosure agreements in place regarding its content!

However, I can provide enough to give you an example of what I find happening....

this is in my main script MStream.pl ....

Code:
# Use insurance submissions object
use MStreamInsSubs;

# create insurance submissions object
my $ins = MStreamInsSubs->new();

# process insurance submissions
$ins->process;

# kill object
$ins = undef;

# Use insurance completions object
use MStreamInsComps;

# create mortgage completion object
$ins = MStreamInsComps->new();

# process mortgage completions
$ins->process;

# kill object
$ins = undef;

the error this produces is....
[Tue Sep 13 11:03:49 2011] MStream.pl: Can't locate object method "insuranceSubValidate" via package "MStreamInsComps"

this is the top of both scripts...

MStreamInsSubs.pm
Code:
# Set Package Name Space 
package MStreamInsSubs;

# Use SQL Module 
use MStreamSQL;

# Use Helper OOPM 
use MStreamHelper;

# Require Insurance Submission Validate include
require "MStreamInsSubValidate.pl";

# Add Inheritance 
our @ISA = ('MStreamHelper');

# Public Class Variables 
our $VERSION = '1.01';

MStreamInsComps.pm
Code:
# Set Package Name Space 
package MStreamInsComps;

# Use SQL Module 
use MStreamSQL;

# Use Helper OOPM 
use MStreamHelper;

# Require Insurance Submission Validate include
require "MStreamInsSubValidate.pl";

# Add Inheritance 
our @ISA = ('MStreamHelper');

# Public Class Variables 
our $VERSION = '1.00';

So why doesn't the MStreamInsSubValidate.pl script (require) get loaded into both OOP modules?

I'm assuming it's loaded into the first module (MStreamInsSubs.pm), and ignored in the second module (MStreamInsComps.pm).

I thought all 'require' statements were loaded at runtime so shouldn't the helper script (require) get loaded as the OOP module object is instantiated?

Dunno, perhaps you can advise why I'm a getting this behaviour?




"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
ahh... now I get it...

The problem is this. The require within MStreamInsSubs loads the MStreamInsSubValidate.pl and the functions in here are now loaded into the MStreamInsSubs namespace.

When the second require is hit, it will know the file is already loaded and not read it again, so the functions don't get imported into the MStreamInsComp namespace.

Really you should wrapper the functions in MStreamInsSubValidate into an object and then get MStreamInsSubs and MStreamInsComps inherit from MStreamInsSubValidate, like you already do with MStreamHelper.

An alternative (which I would have to try myself to check it would work) is to require MStreamInsSubValidate.pl within the MStreamHelper module. Since you inherit this within both modules it may work, but you would also pollute the namespace of any other modules you inherit within, so this may not be a suitable solution. The previous option is definitely the cleaner one.

Does this make sense? I'll try and put some examples up when I get some free time later.

Cheers,
Scott
 
Cool, as i said I kinda guessed that's what was happening, perl being too efficient for its own (my own) good! only loading the script the once!

I agree that putting it in the MStreamHelper module is poluting it too much as several other modules use the helper module and don't need that validate script, infact each type of process (mortgage / insurance / loan) have their own validate script that the subs/comps use , so it would mean putting 3 validate scripts into the helper module making it seriously poluted and in my mind destroying the point of making it OOP and only inheriting / loading what is required by each module / script.

I didn't make it OOP as it seemed overkill for what is essentially an 'include' and if I run each process individually in separate scripts, subs , then comps , it works fine, so I'm not sure I will bother refactoring.

However, it's always nice to be sure you understand what is going on and why errors occur ;-)

Thanks for your input, it's much appreciated.



"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
My apologies - I did not read your comments at the bottom. Yes, you were quite right in your assessment. I'll try and pay more attention in future ! :~/

I also realised I was probably not very clear about the OOP part. What I meant was creating a new module and then using the require in that. Then having both modules inherit the wrapper module so the functions get imported into their namespace. This should make your refactoring quite minimal.

Cheers,
Scott

 
no worries Scott, thanks for your help.

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
ok... so dog with a bone springs to mind...

I have not been actively coding much in perl for a few years - switched to java a little while ago for a number of reasons, mainly unit testing and speed.... but that is another story... The old grey matter was nagging me that there was another alternative to this - as there usually is in perl, so I played a little with how things get imported into the namespace and found the following to work ok for me:

1. Add a package name to the MStreamInsSubValidate.pl before you define the subs, i.e. as follows:

package MStreamInsSubValidate;

2. Change the @ISA array in MStreamInsSubs and MStreamInsComp to include the package name above, i.e.:

our @ISA = ('MStreamHelper', 'MStreamInsSubValidate');

That should hopefully work for you.

The package statement stops to the MStreamInsSubValidate.pl from getting imported directly into the MStreamInsSubs namespace and then allows you to gracefully use it's functions from either the MStreamInsSubs and MStreamInsComp namespaces with the @ISA.

Cheers,
Scott
 
ahh, so although it isn't strictly a module nor a proper OOPM , you can still force the include script to have a namespace and use the @ISA to implement inheritance.

Nice one Scott!

Pitty I can't give you any more stars, you certainly deserve them!

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Google Rank Extractor -> Perl beta with FusionCharts
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top