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

I have an OO parser in two classes Frontend and Backend::Frontend. Frontend inherits from Backend.

Backend parses a file and invokes Frontend::method via a callback for specific chunks of the input document. For instance, it may encounter an element named 'glark', so it calls Frontend::glark($args).

These Frontend methods transform the arguments in some way then either return a string, or recursively call a Backend method to break the input down further. An example of the latter is:

sub Frontend::glark { my ($self,$args) = @_; return 'glark='.$self->backend_method($args); }

This produces the expected output even for complex documents. The problem, I have discovered, is related to the calling of the parent class' methods by Frontend -- the method is invoked correctly, but, as you would expect, the Backend method is invoked on a Backend::Frontend object, which causes no end of problems.

Or, to put it another way:

  1. Backend invokes ($self->{frontend})->frontend_method. (ref($self) eq 'Frontend').
  2. Frontend::frontend_method calls $self->backend_method (intending to dispatch to Backend, as Frontend does a "use base 'Backend'"). (ref($self) eq 'Frontend').
  3. Backend::backend_method is invoked correctly, but now of course ref($self) eq 'Frontend'. Thus, when we do step 1 again later we call the frontend_method of a Frontend object of a Frontend object... This blows up.

I'm sure this problem just represents a basic misunderstanding of Perl OO. I can probably hack around it, but I'd like to know the Right Way. :-)

Replies are listed 'Best First'.
Re: OO Parser Class with Callbacks - Confusion
by merlyn (Sage) on Dec 04, 2006 at 03:32 UTC
    It looks to me like Frontend has-a Backend, not Frontend is-a Backend. Can you describe further why you think having shared reused code and protocol was useful in your design?

      You know, I think you might have nailed it. Intuitively that seems correct.

      I did it this way to divide the parsing of the input file from the format of the output. So the backend would say "I've found a glark element", and frontend A may say "Ignore it", while frontend B may say "Concatenate it with the preceding output".

      The plan was for the client to say:

      my $obj = Backend->new(frontend=>FrontendClass);

      But, as you point out, far more sensible is for them to say:

      my $obj = Frontend->new;

      Then to have Frontend use Backend. :-) Thank you very much!

        Yep, that works perfectly. I had a feeling it was a fundamental mistake. :-)

        I now use Frontend directly like this:

        my $obj = Frontend->new; $obj->parse($file);

        Frontend inherits from Backend, and Frontend doesn't provide a _parse_ method, so it dispatches it up the chain to Backend. Backend does have this method and starts parsing the file. When it hits a token it calls

        $self->handle(name=>'token_name',args=>['arg1','arg2'])
        which is a generic dispatch mechanism in Backend.

        The code for _handle_ is simplified now because it does something like:

        if ($self->can($token)) { return $self->$token($args); }

        IOW, it looks for a method with the same name as the token in the current class and when it fails it passes it to Frontend which does implement said method.:-)

Re: OO Parser Class with Callbacks - Confusion
by GrandFather (Saint) on Dec 04, 2006 at 03:07 UTC

    There may be better solutions depending on just what you need to do, but it looks to me like you could set a flag on the object to say that it is now a backend object. Somewhat clunky, but maybe a low effort way to fix the problem.


    DWIM is Perl's answer to Gödel