Inherited class methods and special variables

J

Jim Schueler

Here is some sample code that uses inherited class methods:

sub parseHTML::docomment {
my $comment = shift ;
print $comment, "\n" ;
}

sub parseASP::AUTOLOAD {
use vars qw( $AUTOLOAD ) ;

my $key = $AUTOLOAD ;
my $package = __PACKAGE__ ;
$key =~ s/^${package}::// ;

eval "parseHTML::$key( \@_ )" ;
}

sub parseASP::doParse () {
...
local $/ = undef ;
$content = []
$buf = <HTMLFILE> ;
$buf =~ s|<!--(.*?)-->|'<!-- '.&docomment( $1, $comments ).'-->'|seig ;
...
}

sub parseASP::docomment {
my $comment = shift ;
print $comment, "\n" ;
}

&doParse() ;


The code listed above works fine, outputting each comment of an HTML file.

If I delete the last function, parseASP::docomment(), then the inherited
function parseHTML::docomment() should behave identically. However, this
time, the code outputs a bunch of blank lines.

My best theory is that the first argument, $1, is passed as a reference to a
local special variable that goes out of scope. But common sense tells me that
anything that goes on the stack should still be there when I pull it off.
Having lost my mind trying to figure this out, any insight or explanation
would be greatly appreciated.

-Jim
 
N

nobull

Here is some sample code that uses inherited class methods:

No it does not.

What you post is code that crys out to be rewritten using method calls
inheritance but actually uses subroutine call autoloading to fake
inheritance.

I may address that in another follow-up.

But your problem has nothing to do with that.
docomment( $1, $comments )
My best theory is that the first argument, $1, is passed as a reference to a
local special variable that goes out of scope. But common sense tells me that
anything that goes on the stack should still be there when I pull it off.
Having lost my mind trying to figure this out, any insight or explanation
would be greatly appreciated.

Actually you have not lost your mind. You have in fact got it right
except that $1 is not a special local variable, it is a special
_global_ variable.

I have described this problem a number of times in the newsgroup that
replaced this one when this one ceased to exist many years ago.

By passing $1 as a subroutine argument you create an alias to the
global variable $1. The global variable $1 magically always refers to
the last regex evaluated in the current or parent stack frames. This
means the value of $1 changes as you go in and out of scopes but it's
still the same variable. The solution is never to pass $1 et al to
subroutines without quoting.

Regard...

my $r = \$1;

'one' =~ /(.*)/;
print "$1 $$r\n"; # one one
{
{
'two' =~ /(.*)/;
print "$1 $$r\n"; # two two
}
print "$1 $$r\n"; # one one
}

As previously mentioned this newsgroup does not exist (see FAQ).
Please do not start threads here.
 
N

nobull

Here is some sample code that uses inherited class methods:

No it does not.

What you post is code that crys out to be rewritten using method calls
inheritance but actually uses subroutine call autoloading to fake
inheritance.

I may address that in another follow-up.

I addresses your real problem in my previous follow-up.

But now I want to talk about something else
sub parseASP::AUTOLOAD {
use vars qw( $AUTOLOAD ) ;

my $key = $AUTOLOAD ;
my $package = __PACKAGE__ ;
$key =~ s/^${package}::// ;

eval "parseHTML::$key( \@_ )" ;
}

Using symbolic references references is usually a bad idea. Using
eval(STRING) to achieve something that could be achived by symbolic
references is worse.

I very much doubt that you really want to leave the package name in
$key if it is something other than __PACKAGE__. I suspect that either
this will never happen or you would want to strip the package name
regardless.

The code above is confused. Are you expecting __PACKAGE__ to be
'parseASP'? If so then the explicit package qualifier on the
subroutine declaration is redundant. If not then it's unlikely that
the above would work since you'd be looking at the $AUTOLOAD in the
wrong package.

package parseASP;
sub AUTOLOAD {
my ($key) = our($AUTOLOAD) =~ /([^:]*)$/ or die;
goto &{"parseHTML::$key"};
}

Note - this will still have the problem with $1 mentioned in my other
follow-up.

If you can't fix the calling code you can work-around this thus:

sub AUTOLOAD {
my ($key) = do { our($AUTOLOAD) =~ /([^:]*)$/ } or die;
goto &{"parseHTML::$key"};
}

Note: as I said before you'd probably be better off using inheritance
than AUTOLOAD.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top