Search code examples
perlhashargumentsparameter-passinghashref

Perl: What's the proper way to pass a hash ref plus additional keys/values as one hash ref?


The purpose is to only ammend the hashref argument being passed to the function, but not modify the original hashref.

{
    my $hr = { foo => q{bunnyfoofoo},
               bar => q{barbiebarbar} };

    foo( { %$hr, baz => q{bazkethound} } );
}

sub foo {
   my $args = shift // {};
}

I think the above would work, but am not sure there is a better way (other than modifying the orginal ref before passing).


Solution

  • Your code is as simple as it can be. You need to pass a hash and you don't want to modify the existing hash, so you need to create a new hash. That's what { } does.

    The underlying problem is foo takes a hash ref instead of a key-value list.

    sub foo {
       my %args = @_;
       ...
    }
    

    You can still do everything you did before:

    foo( foo => 'bunnyfoofoo', bar => 'barbiebarbar' );
    

    my $hash = {
       foo => 'bunnyfoofoo',
       bar => 'barbiebarbar',
    };
    foo( %$hash, baz => 'bazkethound' );
    

    There are two advantages.

    1. You don't have to use { } all over the place.

    2. You can modify the argument safely.

      This is buggy:

      sub f {
         my $args = $_[0] // {};
         my $foo = delete($args->{foo});
         my $bar = delete($args->{bar});
         croak("Unrecognized args " . join(', ', keys(%$args)))
            if %$args;
         ...
      }
      

      This is ok:

      sub f {
         my %args = @_;
         my $foo = delete($args{foo});
         my $bar = delete($args{bar});
         croak("Unrecognized args " . join(', ', keys(%args)))
            if %args;
         ...
      }