Search code examples
perlhashsubroutine

how to pass a hash along with other arguments to a subroutine in perl?


my code:

$self->commitToPerforce($network_name[0], {"size_of_table=>$row->{numRecords}"});

sub commitToPerforce {
    my $self = shift;
    my $network = shift;
    my %metadata = shift;

    open my $FH, ">$local_metadata_file" || die "Could not open file $local_metadata_file";
    print $FH Dumper(%metadata);
    close $FH;
}

problem is, this is what's getting into the file:

$VAR1 = 'HASH(0x320adf0)';
$VAR2 = undef;

not what I'm looking for.

Also tried this:

print $FH Dumper(\%metadata);

which just gives me this:

$VAR1 = {
      'HASH(0x223cea0)' => undef
    };

I want the contents of the hash. Not the reference to the hash.

getting closer now:

my $hash = {"size_of_table=>$row->{numRecords}"};
$self->commitToPerforce($network_name[0], $hash);

   open( my $FH, ">", $local_metadata_file ) || die "Could not open file $local_metadata_file";
print $FH Dumper($metadata);
close $FH;

results in:

 $VAR1 = {
      'size_of_table=>0' => undef
    };

what's with the 'undef'??

oh. i see it now. my hash should not be a single string.

and just because there's no where else for me to gripe: why is it a good idea to spend so much time thinking about my data structures in this way?


Solution

  • Here are some comments on your code

    • I hope the call to commit_to_perforce is in a different file from the method definition?

    • It is often much clearer to define a hash parameter separately and then pass a reference to it, rather than passing an anonymous hash directly in the parameter list

    • Within a method, it is usually best to shift the vlaue of $self off the parameter list, and then do a list assignment for the rest of the parameters

    • You should use the three-parameter form of open, and either check that it succeeded with a die string that includes $! to give the reason for the failure, or just use autodie.

      Because of the precedence of the || operator, your code checks the truth of the string ">$local_metadata_file" instead of the return value from open. You can either use the low-precedence or operator instead or put parentheses around the parameters to open

    • It is common practice to reserve upper case letters for global identifiers, such as the package Dumper. Local variables should normally be named using lower-case letters, numbers, and underscore

    Taking all of that into account, here's how your code should look

    my %meta = (
      size_of_table => $row->{numRecords},
    );
    
    $self->commit_to_perforce($network_name[0], \%meta);
    

    sub commit_to_perforce {
      my $self = shift;
      my ($network, $metadata) = @_;
    
      open my $fh, '>', $local_metadata_file
          or die "Could not open file '$local_metadata_file' for output: $!";
      print $fh Dumper $metadata;
      close $fh;
    }
    

    I hope this helps