Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Pushing hash ref onto array ref

by Bod (Chaplain)
on Apr 11, 2021 at 22:18 UTC ( #11131110=perlquestion: print w/replies, xml ) Need Help??

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

A module I am creating has a blessed hash ref as is common. One of the hashes is a reference to an array of anonymous hashes created like so:

sub new { my $class = shift; my %attrs = @_; my @products = ({ 'id' => 0, 'name' => 'Test', 'description' => 'Some test data', 'qty' => 1, 'price' => 1000, }); $attrs{'trolley'} = \@products; return bless \%attrs, $class; }
Later on I want to push another anonymous hash onto @products.

What is the best way to do this?
Both of these push lines appear to work identically in testing

sub add_product { my ($self, $product_data) = @_; # create $new_product hasfref push $self->{'trolley'}, $new_product; push @{$self->{'trolley'}}, $new_product; }
However, I suspect there is some subtle difference between the two which might trip me up in the future!

Is there a practical difference and is there a 'best' option to use?

Replies are listed 'Best First'.
Re: Pushing hash ref onto array ref
by AnomalousMonk (Bishop) on Apr 11, 2021 at 23:23 UTC

    The "subtle difference" is that push-ing to an array reference was an experimental feature (added circa-5.10 IIRC | added with Perl 5.14, removed as of Perl 5.24) that is now removed. For this reason, I would avoid it even if your particular version of Perl still supports it. (Update: If you intend ever to publish your module, I would absolutely avoid it!)

    Win8 Strawberry 5.30.3.1 (64) Sun 04/11/2021 19:15:44 C:\@Work\Perl\monks >perl use strict; use warnings; use Data::Dump qw(dd); my %attrs = qw(foo 1 bar 2);; my @products = ({ 'id' => 0, 'name' => 'Test', 'description' => 'Some test data', 'qty' => 1, 'price' => 1000, }); $attrs{'trolley'} = \@products; my $self = \%attrs; my $new_product = { qw(id 1 name Widget) }; push $self->{'trolley'}, $new_product; # push @{ $self->{'trolley'} }, $new_product; dd \%attrs; ^Z Experimental push on scalar is now forbidden at - line 22, near "$new_ +product;" Execution of - aborted due to compilation errors.


    Give a man a fish:  <%-{-{-{-<

      I'd use push @{ $hash->{'key'} }, $new out of habit personally, but if you've got a new enough perl (post 5.24.0 according to perlref; you can use back to 5.20 with a feature declaration) you could use the new postfix deref syntax push $hash->{'key'}->@*, $new instead.

      Edit: Clarified version requirement.

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

        I've been making a point of using "perlref: Postfix Dereference Syntax". It removes the need for nested braces and brackets (e.g. %{$aref->[$i]} and @{$href->{$key}}) which can be confusing. It also reads linearly; i.e. ref->deref_to (e.g. $ref->%*) vs. deref_to{ref}.

        For very simple dereferencing, I often find myself using the older (original) syntax (e.g. $$scalarref). This is no doubt out of years of habit and muscle memory. I still think $scalarref->$* is clearer and I try to remember to use that; it also adds consistency to my code.

        I also find "perlref: Postfix Reference Slicing" to be a lot clearer; especially when the initial reference is a complex variable itself.

        Of course, that all requires a sufficiently new version of Perl. For instance, I can't use that for $work where I'm constrained to 5.16; for personal code, where I'm using the latest Perl (currently 5.32) that's not an issue.

        — Ken

      (Update: If you intend ever to publish your module, I would absolutely avoid it!)

      Yes...this module is probably of sufficient utility to be heading for CPAN so expect a few more questions about it and an RFC when I get that far...

Re: Pushing hash ref onto array ref
by Marshall (Canon) on Apr 11, 2021 at 23:25 UTC
    Well, in my testing, for line "push $self->{'trolley'}, $new_product;", I get "experimental push on a scalar now forbidden". So I would not do that! Your second version, push @{$self->{'trolley'}}, $new_product; appears to be "the answer".

    update: I was using Perl 5.24. When I see "experimental", I will "play with" the feature. But not put it into production code. In this case, even if #1 had worked, I would use #2 because the code is more clear.

      I was doing my testing on the server where the code is going to be running which uses v5.16.3 which explains why you get warnings I don't.

      I should have tried it locally where I have v5.32.1 but it didn't even occur to be that there might be a versioning issue!

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (5)
As of 2021-05-11 17:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Perl 7 will be out ...





    Results (120 votes). Check out past polls.

    Notices?