geektron has asked for the wisdom of the Perl Monks concerning the following question:

i keep getting errors on this ... so i guess it's time to ask for more help. here's the boiled-down classes:
package Handler; use strict; use CGI; sub new { my $self = shift; return bless { _cgi => CGI->new() }, $self; } sub cgi { my $self = shift; my $caller = caller(); return ( $caller eq 'Handler' ? $self->{_cgi} : $self->SUPER::->{_c +gi} ); } package HandlerMethods; use strict; use base qw/ Handler /; sub doSomething { my $self = shift; my $page = $self->cgi->param('foo'); return 1; }
now, problem is, i can't get the superclass *data*. in the subcalss,  $self->cgi is always undef, and i know that's because the subclass is calling the superclass *method* but not finding the CGI object in itself ( because it's superclass data ). i've tried caller to make sure the calling package isn't the superclass ( obviously ).

i know the syntax *should* be easy, but i'm missing it.

Replies are listed 'Best First'.
Re: accessing superclass data
by derby (Abbot) on Jul 30, 2003 at 19:39 UTC
    Is the data really in the superclass? Nope. At least not in your boiled down example. Since your HandlerMethods is inheriting its new method, the anon array containing _cgi is blessed into HandlerMethods. It should be enough for "sub cgi" to just return $self->{_cgi}. Try this little driver on your example:

    #!/usr/bin/perl use Handler; use Data::Dumper; $x = HandlerMethods->new(); print Dumper( $x );

    -derby

      too much boiling down. yes, the data is in the superclass.

      the subclass isn't inheriting the  new() method in the actual code. and, that seems to be the best fix.

        Did you override new() in the derived class and forget to call SUPER::new?

Re: accessing superclass data
by blokhead (Monsignor) on Jul 31, 2003 at 04:48 UTC
    but not finding the CGI object in itself ( because it's superclass data )
    No! The data is in the object, not the superclass. There's no reason you can't still get it from $self->{_cgi}, because the HandlerMethods object is still a Handler object too -- otherwise you wouldn't have made the former a subclass of the latter.

    Just change this:

    return ( $caller eq 'Handler' ? $self->{_cgi} : $self->SUPER::->{_ +cgi} );
    .. to this:
    return $self->{_cgi};
    .. and the code should do what you want. Your new constructor as you have it is fine, and you shouldn't need to change it..

    Never put special logic (like the caller business here) in the superclass: a superclass shouldn't know about its subclasses. I have a feeling you are really overthinking the complexity of inheritance. It's really a lot simpler than you have attempted here -- it Just Works. Write the method to work on your Handler objects, and it will Just Work for the subclasses too.

    You should really reread Perl's OO documentation (perlbot, perltoot, perlboot, perlobj, to name a few), specifically about inheritance and SUPER.

    SUPER:: comes into play when the subclass wants to refine the behavior of an existing method. You tried to use SUPER:: from the superclass (and with a hash dereference, not a method), which is definitely not what you want here.

    Here's an example of a correct use of SUPER. Say you want HandlerMethods to refine the behavior of cgi method of Handler:

    package HandlerMethods; sub cgi { my $self = shift; ## first, get whatever the superclass would return my $cgi_obj = $self->SUPER::cgi; ## then we can slightly refine.. $cgi_obj->param('HandlerMethods', 1); return $cgi_obj; }
    Notice how HandlerMethods objects still have a cgi method that behaves just as a Handler object does, but it just adds a little something.

    I hope I cleared a few things up!

    blokhead

      i will agree with you on the overthinking of OO 'stuff'. i do it all the time, mostly because it's 'supposed to be hard' or something. then again, programming is 'supposed to be hard', but it's not *all* that difficult.

      the problem, originally, really was in an unnecessarily overridden subclass constructor. rather than calling Super::new(), the subclasses were instantiating enpty hashrefs. there *was* nothing to return via the superclass accessor that way.

      next time, i'll have to take more care i nthe 'boiled down' code ... what it *should have read* is:

      package HandlerMethods; use strict; use base qw/ Handler /; sub new { my $self = shift; return bless {}, $self; } sub doSomething { my $self = shift; my $page = $self->cgi->param('foo'); return 1; }
      and there's a real issue, because there *is* no CGI object in the subclass now.