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

I'd like to subclass XML::LibXML::Document and add some additional properties. This is no trouble, however, after sublcassing, I noticed that my reference to XML::LibXML::Document is not an instance of a hash ref but a anonymous scalar ref. When I try to add additional key/value pairs to my reference, it obviously fails.

Is there any way I could turn this anonymous scalar reference into a hash reference? My constructor follows:

sub new{ my ($class) = @_; my $self = $class->SUPER::new('1.0','UTF8'); my $root; my @listeners; # fails! $self->{'Listeners'} = @listeners; bless($self, $class); }

Replies are listed 'Best First'.
Re: Anonymous Scalar Ref to Hash?
by Zaxo (Archbishop) on Sep 05, 2002 at 01:26 UTC

    Here is is with hash value error corrected and obvious use of @_.

    sub new{ my $class = shift; # changed to take class off @_ my $self = $class->SUPER::new('1.0','UTF8'); # my $root; #unused my @listeners = @_; # assuming that's what you want $self->{'Listeners'} = [@listeners]; # hash value must be scalar bless($self, $class); }

    After Compline,
    Zaxo

      my @listeners = @_; # assuming that's what you want $self->{'Listeners'} = [@listeners]; # hash value must be scalar
      There's no need for copying. You can use a reference to the original array:
      $self->{'Listeners'} = \@listeners;
      A small thing, but something worth keeping in the back of your mind.
Re: Anonymous Scalar Ref to Hash?
by blokhead (Monsignor) on Sep 05, 2002 at 01:21 UTC
    That's an interesting situation. A possible solution would be to let your subclass have its own private table of instances, and use the scalar reference as a key to that table, as such:
    package MyDoc; @ISA = qw(XML::LibXML::Document); my %instance_hashes; sub new { my $class = shift; my $self = $class->SUPER::new('1.0', 'UTF8'); my @listeners = (); # initialize private hash data $instance_hashes{$self} = {}; $self->listener(\@listeners); bless $self, $class; } # accessor / mutator sub listener { my $self = shift; if (@_) { $instance_hashes{$self}{Listeners} = shift; } return $instance_hashes{$self}{Listeners}; }
    Here we use the $self reference as the key to %instance_hashes, where we can store info about each instance.

    BTW, please use <code></code> tags in your posts. Also, I changed the line where you set the Listeners to @listeners. The way you had it (in scalar context), it would initialize $self->{Listeners} to the size of @listeners, not the elements of the list. Use a reference to the @listeners array to allow access to it from other methods, which is probably what you had in mind.

    blokhead

Re: Anonymous Scalar Ref to Hash?
by dpuu (Chaplain) on Sep 05, 2002 at 01:14 UTC
    You can't add fields to a scalar; but you could use a wrapper class. The wrapper would hold the doc object as an attribute; and have an autoloader to delegate all method calls to that object. --Dave
Re: Anonymous Scalar Ref to Hash?
by adrianh (Chancellor) on Sep 05, 2002 at 10:43 UTC

    One solution would be to use Class::Delegation. For example:

    package My::LibXML::Document; # all method calls in this class should be # delegated to the object in 'base' use Class::Delegation send => -ALL, to => 'base'; sub new { my $class = shift; my $self = bless { base => XML::LibXML::Document->new('1.0','UTF8'), listeners => [1,2,3], # or whatever }, $class; return($self); }; sub listeners { my $listeners = shift->{listeners}; return(@$listeners); }; package main; my $o = My::LibXML::Document->new; print $o->encoding, "\n"; # same as doing $o->{base}->encoding; print join(", ", $o->listeners), "\n";

    Unless your code explicitly checks that My::LibXML::Document isa XML::LibXML::Document you should bee fine.