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

Greetings, fellow Monks!

I've been through the Object Oriented stuff here, but can't seem to locate anything that relates to my current situation. I am trying to create some process logging classes for a web application at work. The basic structure is this:

BaseClass.pm | +-> Log.pm | +-> Writer.pm +-> Reader.pm

The Log.pm class (BaseClass::Log) inherits some general configuration stuff, a Database handle and other little things needed for the application. The Log.pm contains the functions that would be shared between the Reader (BaseClass::Log::Reader) and Writer (BaseClass::Log::Writer); namely primary key lookup functions and the like. The Writer.pm and Reader.pm contain only the methods necessary to write and read from the log tables.

The Log.pm has an @ISA=qw(BaseClass); Reader.pm and Writer.pm both have @ISA=qw(BaseClass::Log). The object is being blessed (2 argument) in the BaseClass.pm file, and all subsequent modules make a call to $class->SUPER::new.

Everything seems to work fine for the first creation (Writer to Log), but upon calling $class->SUPER::new from the Log object, the class still reads "BaseClass::Log::Writer".

What am I doing wrong?

Replies are listed 'Best First'.
(Ovid) Re: Objects and Inheritance
by Ovid (Cardinal) on Nov 21, 2001 at 04:54 UTC

    If you have an class, Foo::Bar, that inherits from Foo, and you call:

    my $obj = Foo::Bar->new;

    It doesn't matter if the constructor is in Foo or Foo::Bar, if you're using the two argument form of bless. Your referent will still be tagged with Foo::Bar. You want this behavior, or else inheritance would break. If you want a Foo object, instantiate one.

    If you're trying to figure out if Foo::Bar is a Foo, try this:

    if ( $obj->isa( 'Foo' ) ) {...}

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: Objects and Inheritance
by Bobcat (Scribe) on Nov 21, 2001 at 05:01 UTC

    Upon further reading, I wasn't specific enough, I suppose.

    Perl gives me an error upon trying to create a new BaseClass::Log::Writer object

    When I step through the code, I get a call to the Writer.pm module's new() sub with "BaseClass::Log::Writer" as the class. This is good.

    I then call $class->SUPER::new which takes me into the Log.pm module's new sub. Here's where things are funky. I assume the class should now be "BaseClass::Log", but it's showing as "BaseClass::Log::Writer" which barfs when I call $class->SUPER::new.

    Here are the various constructors.

    BaseClass Constructor:

    package BaseClass; sub new { my $class = shift @_; my $self = {}; $self = bless $self, $class; # Re-read the config file if it has changed... my $mtime = ( stat(CONFIG_FILE) )[9]; if ($mtime != $config_time) { ($config, $config_time) = &_read_config(CONFIG_FILE); } return $self; }

    Log.pm Constructor:

    package BaseClass::Log; @ISA = qw( BaseClass ); sub new { my $class = shift; my $self = $class->SUPER::new; my (%opt) = ( @_ ); $self->{opt} = \%opt; # Connect to the database. $self->{dbh} = $self->connect_db('hits') || return undef; return $self; }

    Writer.pm Constructor

    package BaseClass::Log::Writer; @ISA = qw( BaseClass::Log ); sub new { my $class = shift @_; my $self = $class->SUPER::new; my (%opt) = (@_); # Standard fields for the Log module go in this array. @self::_properties = qw( type_id class_id subclass_id severity process_id text_info program_name module_name unix_pid host_name purge_date ); # We can set up some defaults for process and such. $opt{unix_pid} = $$ unless $opt{unix_pid}; $opt{program_name} = $0 unless $opt{program_name}; $opt{hostname} = $ENV{HOSTNAME} unless $opt{hostname}; $opt{module_name} = caller || $opt{program_name} unless $opt{module_name}; $opt{purge_date} = POSIX::strftime("%Y-%m-%d", localtime(time)) unless $opt{purge_date}; $opt{type_id} = 'unknown' unless $opt{type_id}; $opt{class_id} = 'unknown' unless $opt{class_id}; $opt{subclass_id} = 'unknown' unless $opt{subclass_id}; $opt{severity} = 0 unless $opt{severity}; $self->{opt} = \%opt; return $self; }

    I hope this makes it a little clearer.

      Could you be a bit more specific? I am assuming that the following is not your error message:

      Encountered barf in somescript.pl line 12.

      I just created a small test case and it works just fine for me. Are you sure that all of your classes are useing the classes that they inherit from? If your BaseClass::Log forgets to use BaseClass (or perhaps misspells it?), then you will get an error message similar to the following:

      Can't locate object method "new" via package "BaseClass::Log" (perhaps + you forgot to load "BaseClass::Log"?) at D:/Perl/site/lib/BaseClass/Log.pm line 14.

      Admittedly, that error message can be a bit misleading.

      Incidentally, the class that is passed along will be the class that is initially called. It will not be the class you are calling.

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

        That was it... I missed a use in the BaseClass::Log file.

        I assumed we'd get cascaded use, which is wrong.

      SUPER does not change the class that the called method sees. It is still the the same class you call new with. (i.e. the Writer class).

      Even though you're (eventually) calling the BaseClass new method, it's going to get 'BaseClass::Log::Writer' as the class if called (originally) from the BC::L:Writer new method. The error is just in your head :)

Re: Objects and Inheritance
by Bobcat (Scribe) on Nov 21, 2001 at 05:35 UTC
    Thanks to everybody (especially Ovid) for the help. It seems I assumed that 'use' would cascade across files, which it doesn't. Upon adding a "use BaseClass" to the appropriate file, everything works fine.
      Incidentally, use base qw(BaseClass) is kind of handy because it sets inheritance and does a use BaseClass in one shot. It keeps you from forgetting things like this.
Re: Objects and Inheritance
by perrin (Chancellor) on Nov 21, 2001 at 04:48 UTC
    To me, it looks like what you have is correct: your object is a BaseClass::Log::Writer, regardless of what it inherits from. What's the problem?