Subclassing CGI::Pretty dies instantly in ->new , bug?

J

Jeremy Henty

I created a subclass of CGI::pretty and it instantly dies:

$ /data/www-jeremy/cgi-bin/cgi-jeremy
Undefined subroutine Jeremy::CGI::delete
at /data/www-jeremy/cgi-bin/cgi-jeremy line 9

Line 9 is:

my $query = Jeremy::CGI->new;

If I modify the class to inherit from CGI then it works.

Is this a bug or a feature?

Is there a workaround?

Are there any other pitfalls if I inherit from CGI instead of
CGI::pretty ? (I plan to use object-oriented style exclusively.)


Details:

Perl 5.8.7 on Linux 2.6.17.14 , gcc 3.4.3 .

The CGI subclass (works as given but fails if I replace CGI with
CGI::pretty):

use strict;
use warnings;

package Jeremy::CGI;
use CGI;
our @ISA;
@ISA = qw( CGI );

1; # success

The CGI script:

#!/usr/bin/perl

use strict;
use warnings;

use lib qw( /home/jeremy/Personal/Geeky/Perl/Lib );
use Jeremy::CGI;

my $query = Jeremy::CGI->new;

print
$query->header,
$query->start_html("Hi!"),
$query->p("boink"),
$query->ul($query->li("foo"),
$query->li("bar"),);
$query->end_html,
;

Full output of "perl -V":

Summary of my perl5 (revision 5 version 8 subversion 7) configuration:
Platform:
osname=linux, osvers=2.6.9, archname=i686-linux
uname='linux knoppix 2.6.9 #2 smp tue oct 19 23:51:10 cest 2004 i686 athlon-4 i386 gnulinux '
config_args='-ds -e -Dprefix=/usr -Dpager=/bin/less -isR'
hint=recommended, useposix=true, d_sigaction=define
usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
use64bitint=undef use64bitall=undef uselongdouble=undef
usemymalloc=n, bincompat5005=undef
Compiler:
cc='cc', ccflags ='-fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
optimize='-O2',
cppflags='-fno-strict-aliasing -pipe -I/usr/local/include'
ccversion='', gccversion='3.4.3', gccosandvers=''
intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
alignbytes=4, prototype=define
Linker and Libraries:
ld='cc', ldflags =' -L/usr/local/lib'
libpth=/usr/local/lib /lib /usr/lib
libs=-lnsl -ldl -lm -lcrypt -lutil -lc
perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
libc=/lib/libc-2.3.4.so, so=so, useshrplib=false, libperl=libperl.a
gnulibc_version='2.3.4'
Dynamic Linking:
dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib'


Characteristics of this binary (from libperl):
Compile-time options: USE_LARGE_FILES
Built under linux
Compiled at Dec 5 2005 05:39:47
@INC:
/usr/lib/perl5/5.8.7/i686-linux
/usr/lib/perl5/5.8.7
/usr/lib/perl5/site_perl/5.8.7/i686-linux
/usr/lib/perl5/site_perl/5.8.7
/usr/lib/perl5/site_perl
 
U

Uri Guttman

JH> I created a subclass of CGI::pretty and it instantly dies:
JH> $ /data/www-jeremy/cgi-bin/cgi-jeremy
JH> Undefined subroutine Jeremy::CGI::delete
JH> at /data/www-jeremy/cgi-bin/cgi-jeremy line 9

JH> Line 9 is:

JH> my $query = Jeremy::CGI->new;

JH> If I modify the class to inherit from CGI then it works.

you are contradicting yourself. you can't subclass without
inheriting. the namespace of a module HAS NOTHING to do with subclassing
or inheritance. it is an arbitrary namespace and you can call it Foo and
subclass Bar.

JH> Is this a bug or a feature?

JH> Is there a workaround?

you found the fix (not a workaround).

JH> Are there any other pitfalls if I inherit from CGI instead of
JH> CGI::pretty ? (I plan to use object-oriented style exclusively.)

JH> use CGI;
JH> our @ISA;
JH> @ISA = qw( CGI );

replace all that with:

use base 'CGI' ;

uri
 
J

Jeremy Henty

JH> I created a subclass of CGI::pretty and it instantly dies:
JH> $ /data/www-jeremy/cgi-bin/cgi-jeremy
JH> Undefined subroutine Jeremy::CGI::delete
JH> at /data/www-jeremy/cgi-bin/cgi-jeremy line 9

JH> Line 9 is:

JH> my $query = Jeremy::CGI->new;

JH> If I modify the class to inherit from CGI then it works.

you are contradicting yourself. you can't subclass without
inheriting.

I don't see how this comment relates to my problem. I'm not claiming
you can subclass without inheriting. What I have is two modules,
identical except that one subclasses CGI and the other subclasses
CGI::pretty , and the first works and the second breaks. What is
wrong with trying to subclass CGI::pretty ?
...the namespace of a module HAS NOTHING to do with subclassing or
inheritance. it is an arbitrary namespace and you can call it Foo
and subclass Bar.

I'm aware of that. I've actually written code that does that without
problems. It doesn't explain why my module breaks if I replace "use
CGI;" with "use CGI::pretty;" and "@ISA = qw( CGI );" with "@ISA = qw(
CGI::pretty );". I've read the CGI and CGI::pretty perldocs, Googled
and searched perl.doc and found nothing that explains this.
JH> use CGI;
JH> our @ISA;
JH> @ISA = qw( CGI );

replace all that with:

use base 'CGI' ;

Thanks for the tip but it doesn't help the original problem, "use base
'CGI';" works fine and "use base 'CGI::pretty';" dies exactly as
before. So I'm still mystified.

Regards,

Jeremy Henty
 
J

Jeremy Henty

... What I have is two modules, identical except that one
subclasses CGI and the other subclasses CGI::pretty , and the first
works and the second breaks. What is wrong with trying to subclass
CGI::pretty ?

I'm following up to myself to explain further: the reason why this is
so surprising is that CGI::pretty is just a subclass of CGI that
modifies a few methods to produce nicer HTML output. If I rewrite my
CGI script to use CGI::pretty directly then it works.

So the *real* puzzle is this: why does replacing CGI::pretty with a
module that does nothing except inherit from CGI::pretty break things?

In fact "perldoc perltoot" says:

Setting up an empty class like this is called the "empty subclass
test"; that is, making a derived class that does nothing but
inherit from a base class. If the original base class has been
designed properly, then the new derived class can be used as a
drop-in replacement for the old one.

which suggests that CGI::pretty is actually broken since it fails the
empty subclass test. If that's so then at the very least the docs
should say so.

Hope this clarifies my question.

Regards,

Jeremy Henty
 
U

Uri Guttman

JH> I'm following up to myself to explain further: the reason why this is
JH> so surprising is that CGI::pretty is just a subclass of CGI that
JH> modifies a few methods to produce nicer HTML output. If I rewrite my
JH> CGI script to use CGI::pretty directly then it works.

well, for one thing since you don't seem to do anything special in
Jeremy::CGI why do you need that module?

the error you get seems to imply a broken inheritance path as your new
method is calling a delete method up the @ISA tree. when you changed
your module to use CGI::pretty did you change all the CGI to
CGI::pretty? you didn't show that version.


JH> So the *real* puzzle is this: why does replacing CGI::pretty with a
JH> module that does nothing except inherit from CGI::pretty break things?

i looked at the code and it seems it should work so i will bet it is
your code that is somehow broken. nothing personal but that is a good
bet when someone complains about modules by certain authors such as
lincoln stein.

try using the use base idea i mentioned. it does exactly what you want
and it means only one place needs to be changed from CGI to
CGI::pretty. maybe that will fix it or help isolate the problem.

also to make your life easier for testing you can run this directly and
not under a web server. this is much better for debugging many cgi
scripts in general.

if you think (and can prove) this is a real error in CGI::pretty then
you should report it to the author (but not until you can show serious
evidence on your side).

uri
 
J

Jeremy Henty

JH> I'm following up to myself to explain further: the reason why
JH> this is so surprising is that CGI::pretty is just a subclass
JH> of CGI that modifies a few methods to produce nicer HTML output.
JH> If I rewrite my CGI script to use CGI::pretty directly then it
JH> works.

well, for one thing since you don't seem to do anything special in
Jeremy::CGI why do you need that module?

I wanted to inherit from CGI::pretty to refactor some code and when I
did so it promptly broke. I'm giving you a stripped-down example to
spare you the irrelevant details. (That's good practice, right?)
... try using the use base idea i mentioned. it does exactly what
you want and it means only one place needs to be changed from CGI to
CGI::pretty. maybe that will fix it or help isolate the problem.

It did not fix it (though I appreciate you telling me about it)! Here
are the *exact* files I am now using (modulo indentation for clarity)

The CGI script:

#!/usr/bin/perl

use strict;
use warnings;

use lib qw( /home/jeremy/Personal/Geeky/Perl/Lib );
use Jeremy::CGI;

my $query = Jeremy::CGI->new;

print
$query->header,
$query->start_html("Hi!"),
$query->p("boink"),
$query->ul($query->li("foo"),
$query->li("bar"),);
$query->end_html,
;

Jeremy/CGI.pm :

use strict;
use warnings;

package Jeremy::CGI;
use base 'CGI::pretty';

1; # success

And the result is:

Undefined subroutine Jeremy::CGI::delete
at /data/www-jeremy/cgi-bin/cgi-jeremy line 9

If I replace "my $query = Jeremy::CGI->new;" with "my $query =
CGI::pretty->new;", it works. If I replace "use base 'CGI::pretty';"
with "use base 'CGI';", it works. But as it stands, it's broken. It
seems clear that subclassing CGI::pretty just doesn't work.
... to make your life easier for testing you can run this directly
and not under a web server.

I am running it directly. (Believe me, I do read the docs and I am
trying not to waste your time or mine.)
... if you think (and can prove) this is a real error in CGI::pretty
then you should report it to the author

I was hoping someone could tell me whether subclassing CGI::pretty was
supported before I hassled the author.
... (but not until you can show serious evidence on your side).

I've given you the exact files and output, and a quote from "perldoc
perltoot" that says a properly written module should not do this. If
that's not serious evidence I don't know what is!

Regards,

Jeremy Henty
 
U

Uri Guttman

JH> The CGI script:

JH> use lib qw( /home/jeremy/Personal/Geeky/Perl/Lib );
JH> use Jeremy::CGI;

JH> my $query = Jeremy::CGI->new;

JH> Jeremy/CGI.pm :

JH> use strict;
JH> use warnings;

JH> package Jeremy::CGI;
JH> use base 'CGI::pretty';

JH> And the result is:

JH> Undefined subroutine Jeremy::CGI::delete
JH> at /data/www-jeremy/cgi-bin/cgi-jeremy line 9

JH> If I replace "my $query = Jeremy::CGI->new;" with "my $query =
JH> CGI::pretty->new;", it works. If I replace "use base 'CGI::pretty';"
JH> with "use base 'CGI';", it works. But as it stands, it's broken. It
JH> seems clear that subclassing CGI::pretty just doesn't work.

i would call that pretty good evidence. not much you can do but write
the author and send him all of this.

JH> I was hoping someone could tell me whether subclassing CGI::pretty was
JH> supported before I hassled the author.

well, no one seems to have tried it before you did (i don't use ::pretty
and don't do much CGI in general).

JH> I've given you the exact files and output, and a quote from "perldoc
JH> perltoot" that says a properly written module should not do this. If
JH> that's not serious evidence I don't know what is!

like i said, now you have to write to lincoln stein and show him
this. if you were to even find the fix (something in CGI::pretty) he
would likely update it quickly. he is know for reasonable response
times. also you can try reporting the bug with rt.cpan.org which may be
more effective. he should get all bug reports from that on his modules.

as i said, i looked at the CGI::pretty code and couldn't see anything
obvious as to why it wouldn't work. there is one possible issue i can
think of. CGI is noted for doing dynamic loading of many of its
functions/methods and it does its own wierd way. maybe GGI::pretty is
doing something that needs to be done in your module too to force
loading of the delete method? i see this line in CGI::pretty and maybe
it will be a clue for you.

$CGI::pretty::AutoloadClass = 'CGI';

also look into calling SUPER::new() instead of new() in your
module. CGI::pretty does that and it might also help. calling SUPER:: is
common when inheriting constructors.

uri
 
J

Jeremy Henty

... you can try reporting the bug with rt.cpan.org which may be more
effective.

I will. Thanks for the pointer.
I see this line in CGI::pretty and maybe it will be a clue for you.

$CGI::pretty::AutoloadClass = 'CGI';

also look into calling SUPER::new() instead of new() in your
module. CGI::pretty does that and it might also help. calling
SUPER:: is common when inheriting constructors.

I did actually try copying stuff from the CGI::pretty constructor into
mine but nothing I tried worked. Eventually I decided to stop
tinkering and ask for help. Maybe the author can tell me the right
combination of magic.

Thanks again for your comments,

Jeremy Henty
 
A

anno4000

Uri Guttman said:
JH> The CGI script:

JH> use lib qw( /home/jeremy/Personal/Geeky/Perl/Lib );
JH> use Jeremy::CGI;

JH> my $query = Jeremy::CGI->new;

JH> Jeremy/CGI.pm :

JH> use strict;
JH> use warnings;

JH> package Jeremy::CGI;
JH> use base 'CGI::pretty';

JH> And the result is:

JH> Undefined subroutine Jeremy::CGI::delete
JH> at /data/www-jeremy/cgi-bin/cgi-jeremy line 9

JH> If I replace "my $query = Jeremy::CGI->new;" with "my $query =
JH> CGI::pretty->new;", it works. If I replace "use base 'CGI::pretty';"
JH> with "use base 'CGI';", it works. But as it stands, it's broken. It
JH> seems clear that subclassing CGI::pretty just doesn't work.

i would call that pretty good evidence. not much you can do but write
the author and send him all of this.

JH> I was hoping someone could tell me whether subclassing CGI::pretty was
JH> supported before I hassled the author.

well, no one seems to have tried it before you did (i don't use ::pretty
and don't do much CGI in general).


JH> I've given you the exact files and output, and a quote from "perldoc
JH> perltoot" that says a properly written module should not do this. If
JH> that's not serious evidence I don't know what is!

like i said, now you have to write to lincoln stein and show him
this. if you were to even find the fix (something in CGI::pretty) he
would likely update it quickly. he is know for reasonable response
times. also you can try reporting the bug with rt.cpan.org which may be
more effective. he should get all bug reports from that on his modules.

as i said, i looked at the CGI::pretty code and couldn't see anything
obvious as to why it wouldn't work. there is one possible issue i can
think of. CGI is noted for doing dynamic loading of many of its
functions/methods and it does its own wierd way. maybe GGI::pretty is
doing something that needs to be done in your module too to force
loading of the delete method? i see this line in CGI::pretty and maybe
it will be a clue for you.

Your hunch is right about helping a class along to load its methods.
This is a workaround: In .../Jeremy/CLI.pm do

package Jeremy::CGI;
use base 'CGI::pretty';

CGI::pretty->can( $_) for qw( delete header cache);

1; # success

The ->can query has the effect that later calls to the methods
actually succeed. I don't know what exactly happens, just
noticed the effect while looking into this.
$CGI::pretty::AutoloadClass = 'CGI';
also look into calling SUPER::new() instead of new() in your
module. CGI::pretty does that and it might also help. calling SUPER:: is
common when inheriting constructors.

No, it's common when you override the constructor with your own. If
you inherit the constructor, there's no need (and no way) to use
SUPER::.

Anno
 
J

Jeremy Henty

This is another auto-followup to thank everyone who posted
workarounds. I'll still send in a bug report, but first, sleep
beckons.

Jeremy Henty
 
U

Uri Guttman

a> Your hunch is right about helping a class along to load its methods.
a> This is a workaround: In .../Jeremy/CLI.pm do

a> package Jeremy::CGI;
a> use base 'CGI::pretty';

a> CGI::pretty->can( $_) for qw( delete header cache);

a> 1; # success

a> The ->can query has the effect that later calls to the methods
a> actually succeed. I don't know what exactly happens, just
a> noticed the effect while looking into this.

interesting. why his call to new() doesn't trigger the autoload of
delete but CGI::pretty's new call does is the mystery.

a> No, it's common when you override the constructor with your own. If
a> you inherit the constructor, there's no need (and no way) to use
a> SUPER::.

SUPER:: is normally used to call the parent class's initializer which
may not be called by its constructor. or some such variation. i thought
it might be a way to force autoloading of the missing methods in this
case. your call to can() seems to force it but again, why it is needed
is unknown. the OP should still ask stein about this IMO.

uri
 

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

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top