Click to See Complete Forum and Search --> : sub new over-writting sub new?
Ultimater
10-28-2005, 05:18 PM
In almost every standard module I've seen a subroutine like this:
#Module1
sub new {
my $class = shift;
my $self = {};
$someImportantVariable1=314159265358979;
$someImportantVariable2="some info needed";
$someImportantVariable3="more info needed";
bless $self, $class;
return $self;
}
and let's say that Perl is going to "use" two modules at once that both define "new". The second module would define it like so:
#Module2
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
Now let's say we use both modules at once:
use Module1; #defines sub new
use Module2; #also defines sub new
#The sub news will stay unchanged within the module but the Perl Main Program can only reference one at a time
$Module1Reference = new Module1; #uses sub new defined in Module2
$Module2Reference = new Module2; #uses sub new defined in Module2
Now tell me, how will the first module work properly later without the three someImportantVariable's defined globally (assumming that in your main program you will use one of the 1st module's special methods that will require those three varaibles to be defined globally when sub new is called)?
Aren't we doing the same thing everytime we use:
#!/usr/bin/perl -w
use strict;
use warnings;
use CGI qw(:standard);
use CGI::Carp qw(fatalsToBrowser);
use Data::Dumper;
use HTML::Template;
How would Perl know which "sub new" to call on statements like:
my $CGI = new CGI;
(Wouldn't one of the modules after CGI also define "sub new" so that in our main program we end up calling a totally different "sub new" defined by the last module defining it)
fireartist
10-31-2005, 09:32 AM
Have you actually tried running any code?
use strict;
use warnings;
use Data::Dumper;
use CGI;
use HTML::Template;
my $cgi = new CGI;
my $mech = new HTML::Template( filehandle => *DATA );
print Dumper $cgi;
print Dumper $mech;
__DATA__
Removing everything unnecessary from the output shows that each object is blessed into the expected package.
$VAR1 = bless( {
# [snip]
}, 'CGI' );
$VAR1 = bless( {
# [snip]
}, 'HTML::Template' );
'use'ing a module does not import the 'new' subroutine into your namespace.
If you had 'strict' and 'warnings' on, you wouldn't have to worry about subroutines being redefined, as the program give an appropriate error message.
Anyway, it's always best to use this style:
my $cgi = CGI->new;
as the other (indirect) style can have unintended consequences.
Nedals
10-31-2005, 08:32 PM
I'm having some difficulty understanding what you are tying to do.
use Module1;
use Module2;
my $ref1 = new Module1; ## Reference pointing to methods in Module1
my $ref2 = new Module2; ## Reference pointing to methods in Module2
You also want some global variables for Module1, I think.
So why not Export those from module1
package Module1;
use vars qw/@ISA @EXPORT/;
use strict;
use Exporter;
@ISA = qw/Exporter/;
@EXPORT_OK = qw/$var1 $var2 $var3/;
our $var1=314159265358979;
our $var2="some info needed";
our $var3="more info needed";
sub new {
my $self = bless({}, shift);
return $self;
}
Ultimater
10-31-2005, 10:29 PM
What I mean is:
package CGI (http://search.cpan.org/src/LDS/CGI.pm-3.11/CGI.pm);
sub new {
my($class,@initializer) = @_;
my $self = {};
bless $self,ref $class || $class || $DefaultClass;
if (ref($initializer[0])
&& (UNIVERSAL::isa($initializer[0],'Apache')
||
UNIVERSAL::isa($initializer[0],'Apache2::RequestRec')
)) {
$self->r(shift @initializer);
}
if (ref($initializer[0])
&& (UNIVERSAL::isa($initializer[0],'CODE'))) {
$self->upload_hook(shift @initializer, shift @initializer);
}
if ($MOD_PERL) {
if ($MOD_PERL == 1) {
$self->r(Apache->request) unless $self->r;
my $r = $self->r;
$r->register_cleanup(\&CGI::_reset_globals);
}
else {
# XXX: once we have the new API
# will do a real PerlOptions -SetupEnv check
$self->r(Apache2::RequestUtil->request) unless $self->r;
my $r = $self->r;
$r->subprocess_env unless exists $ENV{REQUEST_METHOD};
$r->pool->cleanup_register(\&CGI::_reset_globals);
}
undef $NPH;
}
$self->_reset_globals if $PERLEX;
$self->init(@initializer);
return $self;
}
package HTML::Template (http://search.cpan.org/src/SAMTREGAR/HTML-Template-2.7/Template.pm);
sub new {
my $pkg = shift;
my $self; { my %hash; $self = bless(\%hash, $pkg); }
# the options hash
my $options = {};
$self->{options} = $options;
# set default parameters in options hash
%$options = (
debug => 0,
stack_debug => 0,
timing => 0,
search_path_on_include => 0,
cache => 0,
blind_cache => 0,
file_cache => 0,
file_cache_dir => '',
file_cache_dir_mode => 0700,
cache_debug => 0,
shared_cache_debug => 0,
memory_debug => 0,
die_on_bad_params => 1,
vanguard_compatibility_mode => 0,
associate => [],
path => [],
strict => 1,
loop_context_vars => 0,
max_includes => 10,
shared_cache => 0,
double_cache => 0,
double_file_cache => 0,
ipc_key => 'TMPL',
ipc_mode => 0666,
ipc_segment_size => 65536,
ipc_max_size => 0,
global_vars => 0,
no_includes => 0,
case_sensitive => 0,
filter => [],
);
# load in options supplied to new()
for (my $x = 0; $x <= $#_; $x += 2) {
defined($_[($x + 1)]) or croak("HTML::Template->new() called with odd number of option parameters - should be of the form option => value");
$options->{lc($_[$x])} = $_[($x + 1)];
}
# blind_cache = 1 implies cache = 1
$options->{blind_cache} and $options->{cache} = 1;
# shared_cache = 1 implies cache = 1
$options->{shared_cache} and $options->{cache} = 1;
# file_cache = 1 implies cache = 1
$options->{file_cache} and $options->{cache} = 1;
# double_cache is a combination of shared_cache and cache.
$options->{double_cache} and $options->{cache} = 1;
$options->{double_cache} and $options->{shared_cache} = 1;
# double_file_cache is a combination of file_cache and cache.
$options->{double_file_cache} and $options->{cache} = 1;
$options->{double_file_cache} and $options->{file_cache} = 1;
# vanguard_compatibility_mode implies die_on_bad_params = 0
$options->{vanguard_compatibility_mode} and
$options->{die_on_bad_params} = 0;
# handle the "type", "source" parameter format (does anyone use it?)
if (exists($options->{type})) {
exists($options->{source}) or croak("HTML::Template->new() called with 'type' parameter set, but no 'source'!");
($options->{type} eq 'filename' or $options->{type} eq 'scalarref' or
$options->{type} eq 'arrayref' or $options->{type} eq 'filehandle') or
croak("HTML::Template->new() : type parameter must be set to 'filename', 'arrayref', 'scalarref' or 'filehandle'!");
$options->{$options->{type}} = $options->{source};
delete $options->{type};
delete $options->{source};
}
# associate should be an array of one element if it's not
# already an array.
if (ref($options->{associate}) ne 'ARRAY') {
$options->{associate} = [ $options->{associate} ];
}
# path should be an array if it's not already
if (ref($options->{path}) ne 'ARRAY') {
$options->{path} = [ $options->{path} ];
}
# filter should be an array if it's not already
if (ref($options->{filter}) ne 'ARRAY') {
$options->{filter} = [ $options->{filter} ];
}
# make sure objects in associate area support param()
foreach my $object (@{$options->{associate}}) {
defined($object->can('param')) or
croak("HTML::Template->new called with associate option, containing object of type " . ref($object) . " which lacks a param() method!");
}
# check for syntax errors:
my $source_count = 0;
exists($options->{filename}) and $source_count++;
exists($options->{filehandle}) and $source_count++;
exists($options->{arrayref}) and $source_count++;
exists($options->{scalarref}) and $source_count++;
if ($source_count != 1) {
croak("HTML::Template->new called with multiple (or no) template sources specified! A valid call to new() has exactly one filename => 'file' OR exactly one scalarref => \\\$scalar OR exactly one arrayref => \\\@array OR exactly one filehandle => \*FH");
}
# check that filenames aren't empty
if (exists($options->{filename})) {
croak("HTML::Template->new called with empty filename parameter!")
unless defined $options->{filename} and length $options->{filename};
}
# do some memory debugging - this is best started as early as possible
if ($options->{memory_debug}) {
# memory_debug needs GTop
eval { require GTop; };
croak("Could not load GTop. You must have GTop installed to use HTML::Template in memory_debug mode. The error was: $@")
if ($@);
$self->{gtop} = GTop->new();
$self->{proc_mem} = $self->{gtop}->proc_mem($$);
print STDERR "\n### HTML::Template Memory Debug ### START ", $self->{proc_mem}->size(), "\n";
}
if ($options->{file_cache}) {
# make sure we have a file_cache_dir option
croak("You must specify the file_cache_dir option if you want to use file_cache.")
unless defined $options->{file_cache_dir} and
length $options->{file_cache_dir};
# file_cache needs some extra modules loaded
eval { require Storable; };
croak("Could not load Storable. You must have Storable installed to use HTML::Template in file_cache mode. The error was: $@")
if ($@);
}
if ($options->{shared_cache}) {
# shared_cache needs some extra modules loaded
eval { require IPC::SharedCache; };
croak("Could not load IPC::SharedCache. You must have IPC::SharedCache installed to use HTML::Template in shared_cache mode. The error was: $@")
if ($@);
# initialize the shared cache
my %cache;
tie %cache, 'IPC::SharedCache',
ipc_key => $options->{ipc_key},
load_callback => [\&_load_shared_cache, $self],
validate_callback => [\&_validate_shared_cache, $self],
debug => $options->{shared_cache_debug},
ipc_mode => $options->{ipc_mode},
max_size => $options->{ipc_max_size},
ipc_segment_size => $options->{ipc_segment_size};
$self->{cache} = \%cache;
}
print STDERR "### HTML::Template Memory Debug ### POST CACHE INIT ", $self->{proc_mem}->size(), "\n"
if $options->{memory_debug};
# initialize data structures
$self->_init;
print STDERR "### HTML::Template Memory Debug ### POST _INIT CALL ", $self->{proc_mem}->size(), "\n"
if $options->{memory_debug};
# drop the shared cache - leaving out this step results in the
# template object evading garbage collection since the callbacks in
# the shared cache tie hold references to $self! This was not easy
# to find, by the way.
delete $self->{cache} if $options->{shared_cache};
return $self;
}
(continued in next post)
Ultimater
10-31-2005, 10:45 PM
How come the sub "new" doesn't get hurt:
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
use CGI qw[:standard];
use HTML::Template;
sub new {
return 'no content';
}
my $cgi = new CGI;
my $mech = new HTML::Template( filehandle => *DATA );
print header;
print Dumper $cgi;
print '<br><br><br>';
print Dumper $mech;
__DATA__
Why doesn't the output read: 'no content' twice?
How does Perl know to call the sub "new" defined within the "CGI" package in the instance "new CGI".
How does Perl know to call the sub "new" defined within the "HTML::Template" package in the instance "new HTML::Template".
fireartist
11-01-2005, 07:27 AM
It's not calling a subroutine in another package.
Because the package name (e.g. CGI) is a bareword, it realises you're using the "indirect" notation to call a method, so it's treating the bareword as a package name.
I recommended getting into the habit of always making an explicit method call:
my $cgi = CGi->new;
Below is a demonstration of making a method call when the package name is in a variable.
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
use CGI qw[:standard];
sub new {
print "we got @_\n";
return "foo";
}
my $package = 'CGI';
my $cgi = $package->new;
print Dumper $cgi;
__DATA__
If you try using indirect notation, this will instead call your 'new' subroutine - because $package isn't a bareword:
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
use CGI qw[:standard];
sub new {
print "we got @_\n";
return "foo";
}
my $package = 'CGI';
my $cgi = new $package;
print Dumper $cgi;
__DATA__
Ultimater
11-03-2005, 03:39 PM
Ohhhhh.... Ahhh..... I see what's happening now.
Anything declared within a package only exists within that package.
Then to access anything declared within that package from the PL file, I would need to include the package name followed by the subroutine or variable. Prior to now, I was confusing modules which are designed without even a single package name with modules that use at least one package or two. When declaring subroutines in a module, outside of all packages, they are available to the PL file as though declared dirrectly from the PL file and not externally. However when a module declares subroutines within a package, the subroutine is not available to the PL file without including a package name.
So it seems that the keyword "new" is a built-in method.
fireartist
11-03-2005, 05:17 PM
Almost,
A couple points though:
Every module (.pm file) should declare a new package namespace.
'new' isn't a built in.
The indirect method will work for any name.
my $dbh = connect DBI ('dbi', 'etc');
Have you read perlboot, perltoot, perlmod and perlmodstyle?
Ultimater
11-03-2005, 05:23 PM
connect DBI
is the same as
DBI->connect
Ahhh...
So
new CGI
is the same as
CGI->new
like you said earlier, ahh..... I finally understand clearly what is happening now, thanks for that final peice of information!
edit:
"Have you read perlboot, perltoot, perlmod and perlmodstyle?"
I read parts of them, however I lost the links over time.
fireartist
11-04-2005, 06:52 AM
http://perldoc.perl.org
or at a command prompt
perldoc perlboot