Help with a perl package problem

D

danilche

Hiyall,

I need to write some custom handlers for Apache/mod_perl, and I would
like them to be subclassed. THis is really a Perl problem, not an
Apache or mod_perl problem. I am hoping someone here will be able to
enlighten me about a good way to do this.

The structure is like this:

package Parent;

sub custom_func {
....
}

sub handler {
custom_func;
...
}


package Child;
use base 'Parent';

sub custom_func {
}


1;

The problem is that mod_perl calls Parent::handler or Child::handler
function -- there is no object instantiation, no blessed references,
and no polymorphism. However, I need the Child class to inherit the
handler from parent (which it does), and then within the handler I need
it to call the correct custom_func definition. As it is, whenever
Child::handler is called, it is routed to Parent::handler, but then
Parent::handler always calls Parent's custom_func, not Child's
custom_func.

Basically, I am looking to get polymorphism to work on packages rather
than classes. Is there a reasonably easy way to do it?
 
P

Paul Lalli

I need to write some custom handlers for Apache/mod_perl, and I would
like them to be subclassed. THis is really a Perl problem, not an
Apache or mod_perl problem. I am hoping someone here will be able to
enlighten me about a good way to do this.

The structure is like this:

package Parent;

sub custom_func {
...
}

sub handler {
custom_func;
...
}


package Child;
use base 'Parent';

sub custom_func {
}


1;

The problem is that mod_perl calls Parent::handler or Child::handler

Are you paraphrasing, or do you actually see:
Parent::handler
or
Child::handler
somewhere?

Because if so, I can't see how....
function -- there is no object instantiation, no blessed references,
and no polymorphism. However, I need the Child class to inherit the
handler from parent (which it does),

.... this could possibly be true. Child::handler() is specifically
looking for a subroutine named handler in the package Child. There is
no such subroutine. If however, the code actually says:
Child->handler()
then that's an entirely different animal. In this case, when perl
doesn't find a Child::handler, it will go up the @ISA list until it
finds Parent::handler, which matches the behavior you just described.
and then within the handler I need
it to call the correct custom_func definition. As it is, whenever
Child::handler is called, it is routed to Parent::handler, but then
Parent::handler always calls Parent's custom_func, not Child's
custom_func.

Basically, I am looking to get polymorphism to work on packages rather
than classes. Is there a reasonably easy way to do it?

*If* my assumption is correct, then all you need to do is make sure
your handler routine grabs the class name off of the @_ list, and use
that class to call the handler:

#!/usr/bin/perl
use strict;
use warnings;

package Parent;

sub custom {
print "in Parent's custom!\n";
}

sub handler {
my $class = shift;
print "In $class\'s handler!\n";
$class->custom();
}

package Child;
use base 'Parent';

sub custom {
print "in Child's custom!\n";
}

package main;

Parent->handler();
Child->handler();
__END__

In Parent's handler!
in Parent's custom!
In Child's handler!
in Child's custom!

Hope this helps,
Paul Lalli
 
R

Robert Sedlacek

The problem is that mod_perl calls Parent::handler or Child::handler
function -- there is no object instantiation, no blessed references,
and no polymorphism. However, I need the Child class to inherit the
handler from parent (which it does), and then within the handler I need
it to call the correct custom_func definition. As it is, whenever
Child::handler is called, it is routed to Parent::handler, but then
Parent::handler always calls Parent's custom_func, not Child's
custom_func.

Basically, I am looking to get polymorphism to work on packages rather
than classes. Is there a reasonably easy way to do it?

Not that I know of, though there might be some rather hack-ish approach:

package Parent;

sub foo {
my ( $class ) = @_;
$class->bar();
}

sub handler { die "Parent::handler has to be overridden!" }

package Child;
use base qw/ Parent /;

sub handler {
__PACKAGE__->foo();
}

sub bar {
print "Fhtagn!";
}

Though I'm kinda on the jump, so this is untested and just an idea.
Also, I don't know if there's a way a sub can find out it's current
package when it's imported, which would make this cleaner.

hth, p
 
D

danilche

Are you paraphrasing, or do you actually see:
Parent::handler
or
Child::handler
somewhere?

I don't *see* them, but that seems to be how mod_perl seems to call the
handler -- handler's @_ is empty, that was the first thing I checked,
so I cannot grab the class name from the parameter list.
Child::handler() is specifically
looking for a subroutine named handler in the package Child.

Yes, and it's inherited by Child from Parent -- see 'use base'
directive. The problem is that the handler ends up being evaluated
fully in Parent context, without polymorphism.
 
D

danilche

Not that I know of, though there might be some rather hack-ish approach:

Hmmm. I won't make the handler pure virtual (both Parent::handler and
CHild::handler have to be callable), but an approach like that, while
not quite as clean as I was hoping for, should work. It's kludgey, but
it's way better than than the alternatives I have so far. Thanks for an
idea.
 
P

Paul Lalli

Yes, and it's inherited by Child from Parent -- see 'use base'
directive.

Time for you to follow your own advice. All `use base;` does is
establish the @ISA relationship at compile time. It does not magically
make all calls to one package's subroutines traverse the @ISA array.
That's what the method notation does.

Variant based on my previous post, to illustrate:
#!/usr/bin/perl
use strict;
use warnings;

package Parent;

sub custom {
print "in Parent's custom!\n";
}

sub handler {
print "In Parent's handler!\n";
custom();
}

package Child;
use base 'Parent';

sub custom {
print "in Child's custom!\n";
}

package main;

Parent::handler();
Child::handler();

__END__
In Parent's handler!
in Parent's custom!
Undefined subroutine &Child::handler called at ./clpm.pl line 26.


Paul Lalli
 
D

danilche

Time for you to follow your own advice. All `use base;` does is
establish the @ISA relationship at compile time. It does not magically
make all calls to one package's subroutines traverse the @ISA array.
That's what the method notation does.

<shrug> The Parent's handler gets invoked even if the Child is
specified as the handler package -- and the handler gets no parameters,
so it's clearly not invoked via the method notation. Perhaps mod_perl
workd some magic to traverse the inheritance tree in search of a
defined 'handler' subroutine, but the handler does get called when the
Child package is specified as the request handler package.
 
R

Robert Sedlacek

Hmmm. I won't make the handler pure virtual (both Parent::handler and
CHild::handler have to be callable), but an approach like that, while
not quite as clean as I was hoping for, should work. It's kludgey, but
it's way better than than the alternatives I have so far. Thanks for an
idea.

Don't get me started, I just had a very bad idea about importing a
working "starting" handler with help from string eval :)

But as I said, that'd be a *very* bad idea ;)
 
R

Robert Sedlacek

<shrug> The Parent's handler gets invoked even if the Child is
specified as the handler package -- and the handler gets no parameters,
so it's clearly not invoked via the method notation. Perhaps mod_perl
workd some magic to traverse the inheritance tree in search of a
defined 'handler' subroutine, but the handler does get called when the
Child package is specified as the request handler package.

It might be even just something like

my $handler = $handler_class->can( 'handler' ) or die "...";
$handler->();
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top