http://www.perlmonks.org?node_id=446067

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

Hi
I have a strange problem with my OOPerl module and the AUTLOAD method. Let me explain.... I have a big hash that contains attributes...
my %_attribute_properties = ( _probeset_id => ['????', 'read.required'], ... _affy_align => [ ['????'] , 'read.write.noinit' ] _exons_map => [ { } , 'read.write.noinit' ] ... );
Note that this attributes contains values of different type.
Now I have an AUTOLOAD method to get and set the attributes values. Concept of AUTOLOAD is :
Proble is that the first time that i call:
my %hash = $probeset -> get_exons_map I recieve an error (scalar found where list expected).
Second time no problem, I recieve thet correct type (hash)
Seems that the AUTOLOAD can't access valute type (but only the scalar pointer) at the first time! How can resolve it?

# AUTOLOAD Accesors if ($operation eq 'get') { # can i read the attribute? unless ($self -> _permissions ($attribute, 'read')) { die ("You don't have read permission for $attribute"); } # # Install accessor definition in the symbol table # How AUTOLOAD work: *{$VAR} give access to the symbol definit +ion table so, # the second time that the method get_name is called AUTOLOAD +isn't called cause # get_name is saved in the symbol table *{$AUTOLOAD} = sub { my ($self) = @_; unless ($self -> _permissions($attribute, 'read')) { die ("$attribute does not have read permission!"); } # get the attribute value # TIE-HASH da inserire qui # The attribute could be a scalar or a reference to an arr +ay or hash if (ref($self -> {$attribute}) eq 'ARRAY') { return @{$self->{$attribute}}; } elsif (ref($self -> {$attribute}) eq 'HASH') { return %{$self->{$attribute}}; } else { return $self -> {$attribute}; } }; }elsif ($operation eq 'set') { # Verify if you can set the attribute unless ($self -> _permissions($attribute, 'write')) { die ("$attribute does not have write permission!"); } # set the attribute value $self -> {$attribute} = $newvalue; # Install this mutator in the symbol table *{$AUTOLOAD} = sub { my ($self, $newvalue) = @_; unless ($self -> _permissions($attribute, 'write')) { die ("$attribute does not have write permission!"); } $self -> {$attribute} = $newvalue; }; } # Turn strict refs on use strict 'refs'; # Return the attribute value return $self -> {$attribute}; } # }}}

Replies are listed 'Best First'.
Re: OO Perl and AUTOLOAD
by tlm (Prior) on Apr 08, 2005 at 16:44 UTC

    I think what you want at the very end of your AUTOLOAD method is

    # don't turn strict 'refs' back on return $self ->$AUTOLOAD(@_);
    or better yet
    unshift @_, $self; goto &$AUTOLOAD;

    Update: fixed unshift typo.

    the lowliest monk

Re: OO Perl and AUTOLOAD
by shemp (Deacon) on Apr 08, 2005 at 16:54 UTC
    In the code you provided, you never directly look in the %_attribute_properties. It appears that your accessor only knows the type of the thing being accessed, because you have set the value with the mutator. If you modify the accessor so that it checks if the attribute exists, and if not, find the type of the attribute from the %attribute_properties, then the proper type should be returned.

    As a nitpick, why not return references to the array and hash attributes, then you dont need to play dereferencing games, let the caller, because they need to know the type already...unless of course you want to return deep copies.

      The next chapter of the story:
      # locations _locations => [ ['????'] , 'read.write.noinit.array' + ], _refseqposition => [ { } , 'read.write.noinit.hash' + ], # licrinfo _licr_info => [ ['????'] , 'read.write.noinit.array' + ],
      And type handler
      # Added Type handler sub _check_type { my ($self,$attribute,$type) = @_; $_attribute_properties{$attribute}[1] =~ /$type/; }
      Now AUTOLOAD works good from the caller! THANKS TO ALL!
Re: OO Perl and AUTOLOAD
by tilly (Archbishop) on Apr 08, 2005 at 18:43 UTC