Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I interact with a Perl object that has a hash attribute?

Tags:

object

hash

perl

I have a class with several variables, one of which is a hash (_runs):

sub new
{
    my ($class, $name) = @_;
    my $self = {
        _name => $name,
        ...
        _runs => (),
        _times => [],
        ...
    };
    bless ($self, $class);
    return $self;
}

Now, all I'm trying to do is create an accessor/mutator, as well as another subroutine that pushes new data into the hash. But I'm having a hell of a time getting all the referencing/dereferencing/$self calls working together. I've about burned my eyes out with "Can't use string ("blah") as a HASH ref etc etc" errors.

For the accessor, what is 'best practice' for returning hashes? Which one of these options should I be using (if any)?:

return $self->{_runs};
return %{ $self->{_runs} };
return \$self->{_runs};

Further, when I'm using the hash within other subroutines in the class, what syntax do I use to copy it?

my @runs = $self->{_runs};
my @runs = %{ $self->{_runs} };
my @runs = $%{ $self->{_runs} };
my @runs = $$self->{_runs};

Same goes for iterating over the keys:

foreach my $dt (keys $self->{_runs})
foreach my $dt (keys %{ $self->{_runs} })

And how about actually adding the data?

$self->{_runs}{$dt} = $duration;
%{ $self->{_runs} }{$dt} = $duration;
$$self->{_runs}{$dt} = $duration;

You get the point. I've been reading articles about using classes, and articles about referencing and dereferencing, but I can't seem to get my brain to combine the knowledge and use both at the same time. I got my _times array working finally, but mimicking my array syntax over to hashes didn't work.

like image 207
brydgesk Avatar asked Dec 10 '22 15:12

brydgesk


2 Answers

You are storing references to array or hashes in your object. To use them with standard functions you'll need to dereference them. For example:

@{ $self->{_array_ref_key} }; 
%{ $self->{_hash_ref_key} };

If you need pass parameters to standard function:

push( @{ $self->{_array_ref_key} }, $some_value );
for my $hash_key ( keys %{ $self->{_hash_ref_key} }) {
    $self->{_hash_ref_key}{$hash_key}; ## you can access hash value by reference
}

Also $self->{_hash_ref_key}{$hash_key} syntax is shortcut for $self->{_hash_ref_key}->{$hash_key} (which can make for sense if you see it first time).

Also take a look at corresponding manual page.

like image 159
Ivan Nevostruev Avatar answered Apr 11 '23 08:04

Ivan Nevostruev


Might as well take my comments and make a proper answer out of it. I'll illustrate exactly why your sample code failed.

use warnings;
my $self = {
    _name => $name,
    _runs => (),
    _times => [],
};
bless ($self, $class);

use Data::Dump::Streamer; DumpLex $self;

__END__
Odd number of elements in anonymous hash at …

$self = bless( {
    _name             => undef,
    _runs             => '_times',
    "ARRAY(0x88dcb8)" => undef,
}, '…' );

All the elements in the list form the key/value pairs for the hash whose reference is going to be blessed. () is an empty list, so what you're really expressing is the list '_name', $name, '_runs', '_times', []. You can see that _times moves up to become a value, and the reference [] is stringified as hash key. You get the warning because there's no value left for it; this will be automatically coerced to undef. (Always always enable the warnings pragma.)

Now for the guts part: hash values must be a scalar value. Arrays and hashes aren't; but references to them are. Thus:

my $self = {
    _name => $name,
    _runs => {},
    _times => [],
};
like image 20
daxim Avatar answered Apr 11 '23 10:04

daxim