Beefy Boxes and Bandwidth Generously Provided by pair Networks Russ
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Hash references moving between modules

by scain (Curate)
on Jan 10, 2003 at 17:14 UTC ( #225869=perlquestion: print w/ replies, xml ) Need Help??
scain has asked for the wisdom of the Perl Monks concerning the following question:

Hello Fine Monks,

References are giving me a big headache. Every time I think I have them figured out, Perl gently points out that I don't.

So here is the basic question: how do I access a hash that is created in one package and needed in another? It seems like that should be a simple question with a reasonably simple answer, but I keep banging my head up against a wall trying to get it to work. Below I will put trimmed down versions of my packages to illustrate my question more fully.

Package 1:

package Bio::DB::Das::Chado; use strict; use Bio::Root::Root; use vars qw(@ISA); @ISA = qw(Bio::Root::Root); sub new { my $class = shift; my $self = $class->SUPER::new(@_); # do some work here to extract a DBI $hashref my $cvterm_id; # this scalar is going to be a hashref while (my $hashref = $sth->fetchrow_hashref) { $$cvterm_id{$$hashref{termname}} = $$hashref{cvterm_id}; } return bless {dbh => $dbh, cvterm_id => $cvterm_id}, ref $self ||$self; } sub segment { my $self = shift; my ($name,$start,$end,$class,$version) = $self->_rearrange([qw(NAME START END CLASS VERSION)],@_); # _rearrange is in Bio::Root::Root; I'm allowed to use it # lets the Segment class handle all the lifting. return $self->Bio::DB::Das::Chado::Segment->new($name,$self,$start,$ +end); } 1;
Package 2:
package Bio::DB::Das::Chado::Segment; use strict; use Bio::Root::Root; use vars '@ISA'; @ISA = qw(Bio::Root::Root); sub new { my $self = shift; my ($name,$dbadaptor,$start,$end) = @_; #$dbadaptor is 'Bio::DB::Das::Chado' # now do all kinds of work validating and obtaining info my $cvterm_id = $dbadaptor->{cvterm_id}; # so $cvterm_id should be a reference to the same # hash referenced in the first package, right? return bless {dbadaptor => $dbadaptor, start => $start, end => $end, length => $length, srcfeature_id => $srcfeature_id, cvterm_id => $cvterm_id, name => $name }, ref $self ||$self; } sub features { my $self = shift; # do lots more stuff, mostly to build a sql query my %termhash = %{$self->{cvterm_id}}; # shouldn't this be a reference to the hash ref in this #package's constructor, that in turn is a ref to the # hash ref in the first package? my @keys = grep(/\sgene/i , keys %termhash ); # this fails because %termhash isn't a hash. return; } 1;
Any pointers would be appreciated. Thanks for looking through this code; I hope I usefully trimmed it down.
Thanks,

Scott
Project coordinator of the Generic Model Organism Database Project

Comment on Hash references moving between modules
Select or Download Code
Re: Hash references moving between modules
by derby (Abbot) on Jan 10, 2003 at 17:59 UTC
    For starters, I don't understand both Bio:DB::Das::Chado and Bio::DB::Das::Chado::Segment being subclasses of Bio::Root::Root ... but besides that I also don't think this line is doing what you want:

    return $self->Bio::DB::Das::Chado::Segment->new($name,$self,$start,$end);

    shouldn't that just be:

    return Bio::DB::Das::Chado::Segment->new($name,$self,$start,$end);

    Other than that, are you sure your sql is returning results? If your sql fails, $cvterm_id will never be converted to a hash reference (it will stay a plain scalar) and your code downstream will fail. You probably want something like this to protect the code downstream (or you could check if you have a hash downline):

    my $cvterm_id = {} ; # this scalar is a hashref while (my $hashref = $sth->fetchrow_hashref) { $$cvterm_id{$$hashref{termname}} = $$hashref{cvterm_id}; }

    Then at least %termhash will be a hash but quite possibly an empty one if the sql fails.

    -derby

      Ack, that is what I get for trying to simplify too much. First, Bio::Root::Root is the main class from which most BioPerl objects inherit.

      The first line you mention didn't really look like that in my code, it was

      return $self->_segclass->new($name,$self,$start,$end);
      Where _segclass is a private method that returns the string 'Bio::DB::Das::Chado::Segment'. I was trying to hard to trim things down and simplified one thing to make it wrong.

      It is a good point that I should be checking for returned results. In this case, I know that they are from previous debugging. Nevertheless, I will add the = {}; because that is a good idea.

      Thanks,

      Scott
      Project coordinator of the Generic Model Organism Database Project

Re: Hash references moving between modules
by scain (Curate) on Jan 10, 2003 at 18:22 UTC
    Turns out this was a trick question--the thing that I thought was a hashref really was. It was the next line with the grep that was failing. That regex should have been /^gene/ instead. As a result, the @keys array was empty, making it look later on like I didn't having anything in the hash.

    D'oh!

    Thanks anyway,

    Scott
    Project coordinator of the Generic Model Organism Database Project

Re: Hash references moving between modules
by castaway (Parson) on Jan 10, 2003 at 18:36 UTC
    Hi,
    I don't think your $cvterm_id holds what you think it does at all.
    my $cvterm_id; # this scalar is going to be a hashref while (my $hashref = $sth->fetchrow_hashref) { $$cvterm_id{$$hashref{termname}} = $$hashref{cvterm_id}; }
    $cvterm_id is a scalar with no content at the beginning.
    You get a $hashref from somewhere.
    "$$hashref{cvterm_id}" is extracting the item called 'cvterm_id' from a hash called whatever is in $hashref. Eg. if $hashref = 'fred' then it's looking at element 'cvterm_id' in %fred. I'm not sure thats what you want.
    Likewise the result is being written into a hash with no name (as $cvterm_id is undefined, no idea what that actually does..), in the element called $fred{termname}

    If $cvterm_id is going to be a hash reference, you need to use it like this:

    my $cvterm_id; # this scalar is going to be a hashref while (my $hashref = $sth->fetchrow_hashref) { $cvterm_id->{$$hashref{termname}} = $$hashref{cvterm_id}; }
    If $hashref is also a real hash reference and not just the name of a hash, then you need this:
    my $cvterm_id; # this scalar is going to be a hashref while (my $hashref = $sth->fetchrow_hashref) { $cvterm_id->{$hashref->{termname}} = $hashref->{cvterm_id}; }
    Then the second package should work.

    Try looking at the contents of $cvterm_id in the second package after the while loop, using Data::Dumper for instance. (use Data::Dumper; print Dumper($cvterm_id);)
    I hope that helps,
    C.
    PS: Dereferencing references using the arrow operator is explained on page 253 of the Camel book (3rd edition)

      Hmm... Well, derefrencing a hashref can be done in the way you showed up there, but it is perfectly valid to get a scalar back from a hashref this way as well:
      $scalar = $$hashref{key};
      and assigning into a hashref can be done in the same way:
      my $hashref = {}; $$hashref{key} = $scalar;
      Perhaps taking a look at References quick reference will sum it up nicely.

      Thanks,

      Scott
      Project coordinator of the Generic Model Organism Database Project

        Thanks,
        I noticed that a while after I wrote it. I guess I'm too used to using ->.. I think thats more readable than $$ ..
        C.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://225869]
Approved by pfaut
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (10)
As of 2014-04-18 11:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (466 votes), past polls