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

I recently learned about object oriented programming in Perl and I wanted to convert my scripts to objects..

I have a script which uses XML::Parser, and I also have the start tag handler, the character handler and the end tag handler as methods in the class..

The problem is that when I try to pass references to these methods inside the class, I get the error
Not a code reference as line xx where line xx is the line where the handlers are set...

This is the code from inside the method start_parse

my $parser = new XML::Parser(ErrorContext => 2,Handlers => {Start => \ +&{$self->handle_start}, End => \&$self->handle_end, Char => \&$self->handle_char});

I need to have these handlers as methods because they update state variables held inside the class, so I need to pass in the $self reference to the handler somehow..

Can someone please tell me how to fix this ? Thanks

Replies are listed 'Best First'.
Re: Perl objects and code references
by stephen (Priest) on Apr 23, 2001 at 07:27 UTC
    You're trying to pass an object function call ($self->handle_end()) as an object reference. The code you've got will attempt to dereference $self as a code reference, which it isn't.

    Instead, you need to create an anonymous subroutine that will pass the correct value of $self along to XML::Parser. Anonymous subroutines are neat, if easy to abuse.

    The important thing about anonymous subroutines, also known as closures, is that they hang onto the value of any lexical variables inside it. Read perlman:perlsub for more about closures. So, if I created an anonymous subroutine inside a hash, like so:

    my $self = Foo->new(); my $mysub = sub { $self->increment() };
    ...and then later on used it:
    $mysub->();
    Then the correct value of $self would be have increment() called on it.

    So, in order to fix your problem, you need to create closures around your method calls. I'll leave the rest to you. :)

    stephen

Re: Perl objects and code references
by gildir (Pilgrim) on Apr 23, 2001 at 16:11 UTC
    XML::Parser is little bit cumbersome in 'pure' OO usage. If you are planning making a pure OO code, you should rather use DOM or SAX API. I personaly do not like DOM, as it is kind of non-perlish API. I would suggest XML::Grove with SAX for tree-like API or SAX parser directly for event API.
    Some of this modules use XML::Parser internaly, but this is completly hidden to module user.

    If you are determined to directly use XML::Parser anyway, check out replies to my question here.
    especialy this solution with closures.

Re: Perl objects and code references
by premchai21 (Curate) on Apr 23, 2001 at 07:04 UTC
    # Try just getting rid of the \&s. Or, put every $self->something into {}s.
      I'm afraid that getting rid of the \&'s would result in mallet passing the return values from calling those subroutines to XML::Parser. And putting the code into brackets would do something similar. The result would still be a 'Not a CODE reference'. (Tried it.)

      stephen