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

Dear Monks,

please have a look at the following very simple program:

use XML::LibXML::SAX; my $XMLParser = XML::LibXML::SAX -> new(Handler => MyHandler); $XMLParser -> parse_string( "<a>bla</a>" ); exit(0); package MyHandler; #use base qw(XML::SAX::Base); sub start_document { my ($This, $Data) = @_; print "Caught document start\n"; # $This -> SUPER::characters($Data); } 1;

The code as shown above works like expected. But according to a whole bunch of documentation and examples I have studied, I really should remove the # at the beginning of the respective lines. But if I do so, I get the following error message:

Can't use string ("MyHandler") as a HASH ref while "strict refs" in use at /usr/local/share/perl/5.10.1/XML/SAX/Base.pm line 434. at /usr/local/lib/perl/5.10.1/XML/LibXML/SAX.pm line 99
at test.pl line 6

I have googled many documents where many possible causes of and cures to this message are described, but it seems that none of these documents applies to my problem.

Could somebody help me out of there?

Thank you very much in advance,

Nocturnus

UPDATE: I am using perl 5.10.1 from Debian squeeze 64 bit.

Replies are listed 'Best First'.
Re: Error: Can't use string as a hash ref
by AnomalousMonk (Archbishop) on Apr 21, 2012 at 17:39 UTC

    An error message you are not getting suggests you do not have strictures enabled; had they been, you might have been pointed down the Right Way sooner. IMO, always a good idea to enable strictures – and warnings! (Example code run under Strawberry 5.10.1, but should perform identically under any version.)

    >perl -w -le "my @ra = (X => Y); print qq{@ra}; " X Y >perl -wMstrict -le "my @ra = (X => Y); print qq{@ra}; " Bareword "Y" not allowed while "strict subs" in use at ... Execution of -e aborted due to compilation errors.

      At first, thanks for the hint.

      Of course, all of my scripts usually start with

      #/usr/bin/perl -w use strict;

      But I have stripped out as much as possible to boil the example down to the really important things. In this case, the important thing is that the occurrence of an error message does not depend on using strictures or not (and thus the many documents I found on the web don't apply to my problem), but on the

      use base ...

      line. So I got an error message even without using strictures.

      But you are right in that the error message changes if I put a

      use strict;

      at the beginning of the script. The message is then:

      Bareword "MyHandler" not allowed while "strict subs" in use at test.pl line 5.
      Execution of test.pl aborted due to compilation errors.

      Unfortunately, that wouldn't have helped me either. I still wouldn't have known how to solve the problem. But the comment of choroba pointed me to the right direction (see other comment).

      Thank you very much again,

      Nocturnus

        But adding use strict to your own script made it tell you your actual problem (whether you understood the error message or not), rather than letting it fall through to cause an error in the module. The problem wasn't with OO or your module; it was your use of the "bareword 'MyHandler'", as it says.

        When you use a bareword (a bit of text without a sigil or quotes or anything else to give it context) in a place where barewords aren't specifically allowed (like hash keys or file descriptors), Perl (in non-strict mode) does its best to guess what you mean by it. In most cases, including this one, it turns the bareword into a string, here coming up with "MyHandler", which it happily passes as the argument to your module. Then the module finally chokes on it because it expects a hash (object) reference. Using strict warns you sooner, at the exact point of the problem.

        Aaron B.
        My Woefully Neglected Blog, where I occasionally mention Perl.

Re: Error: Can't use string as a hash ref
by choroba (Cardinal) on Apr 21, 2012 at 14:48 UTC
    If you change
    Handler => MyHandler
    to
    Handler => MyHandler->new
    the code runs again. I do not use SAX, so I am not sure it is the right way.

      Thank you very much for pointing me to the right direction!

      I probably would never have tried it that way since nearly all examples I have found are like my original code.

      Just one comment which might be interesting for others as well:

      At first, since I had not implemented a sub "new" in MyHandler, I was wondering why your solution was working at all. Then I understood that probably the "constructor" ("new") of the base class was called instead which explains why there was no compilation error.

      Nevertheless, I was still unsure what was going on behind the scenes. If really "new" from the base class would have been called, I would have expected that an instance of the base class would have been returned. But this is not the case since "start_document" (from MyHandler) has been executed instead of "start_document" from the base class (the latter would not have output anything to the console).

      So, for me, there was a contradiction. I really would like to understand this, but currently, I don't have the time to dig into the details. Instead, I have done it a way I am considering safe (mainly by copying and pasting examples from the web which made sense IMHO). I just added the constructor to MyHandler like that:

      ... package MyHandler; use base qw(XML::SAX::Base); sub new { my $s_Class = shift(); return (bless ({ }, $s_Class)); } ...

      That way, "new" for sure returns the right type (object reference), and I don't have to worry about possible side effects or unexpected behavior.

      Thank you very much again,

      Nocturnus

        I would have expected that an instance of the base class would have been returned.
        You should read more on Object Oriented Programming. This is not how inheritance works. Try this:
        { package MyBase; sub new { my $class = shift; warn "Constructing $class\n"; bless {}, $class; } } { package MyChild; use base 'MyBase'; } package main; use feature 'say'; my $p = MyBase->new; my $ch = MyChild->new; say for $p, $ch;

        Updated: MyBase quoted in "use base".