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 (Archbishop) 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!