user3802685
user3802685

Reputation: 75

How does the dereferencing in this snippet work?

I am having a hard time wrapping my head around this little snippet of code:

my $ref = \@{$seq->{$label}{$ARGV[4]}};

Can I get some help deciphering this?

Upvotes: 4

Views: 95

Answers (3)

Benjamin W.
Benjamin W.

Reputation: 52102

  • $seq is a hash reference
  • $seq->{$label} returns the value of the $label key in the dereferenced hash
  • That value is another hash, from which we get the value of the $ARGV[4] key
    • @ARGV is the array of command line arguments, $ARGV[4] is the element at index 4
  • All this returns an array reference, which is dereferenced by @{...}
  • Adding the backslash in the front turns it back into an array reference

Summary: it's the reference to the array that is the value of the $ARGV[4] key in the hash returned by $seq->{$label}, and the whole thing could IMHO be written

my $ref = $seq->{$label}{$ARGV[4]};

See Borodin's answer for the difference between \@{$ref} and $ref.

Upvotes: 3

vol7ron
vol7ron

Reputation: 42095

my $ref = \@{$seq->{$label}{$ARGV[4]}};

It's best to work from inside out for order of operation:

  1. $ARGV[4] : the fifth argument passed in through the command line (e.g., ./perlscript.pl "argument1" "argument2" "argument3" "argument4" "argument5.txt")
  2. $seq->{ $label }{ $ARGV[4]} : this is holding a ref to an array, we know this because when you try to dereference it by wrapping it in @{ ... }, you would otherwise receive a warning saying Not an ARRAY reference. Also, in place of variables you could also use bare strings (e.g., $seq->{ 'some label' }{ 'some other label'})
  3. @{ $seq->{ $label }{ $ARGV[4] } } : this is doing the dereferencing, as mentioned in #3
  4. \@{ $seq->{ $label }{ $ARGV[4] } } : the slash is making it a reference again, clarifying that an array reference was being held in the hash
  5. my $ref = \@{ $seq->{ $label }{ $ARGV[4] } }; : your standard variable assignment

We haven't seen much other code, so it's tough to say how much this may need updated. Usually you would want to sanitize your inputs, to make sure no bad or extremely large data is being passed in. Additionally, you would want to make it more meaningful. $seq could be sequence or anything really, $label is not too identifiable, and using any $ARGV as you have done, generally means something else is not being done elsewhere.

Upvotes: 1

Borodin
Borodin

Reputation: 126722

Lets rewrite it like this

my $ref = \@{

    $seq->{ $label }{ $ARGV[4] }

}

The outer my $ref = is an assignment. I presume that's clear

Then @{ ... } dereferences the contents of the braces as an array, and \ then takes a reference to that. The reference cancels out the dereference, so it's identical to

my $ref = $seq->{ $label }{ $ARGV[4] }

except that the dereference will cause the program to die with

Not an ARRAY reference

if the contents aren't a reference to an array

Now we have

$seq->{ $label }{ $ARGV[4] }

which uses $seq as a reference to a hash of hashes, and uses $label as the first-level key and $ARGV[4] (the fifth command-line argument) as the second-level key

That statement was written by someone who I will generously call a poor programmer. I doubt if it was intended to check for the hash value being an array reference, and at the very least $ARGV[4] should be copied to a named variable to make the meaning clear

Upvotes: 6

Related Questions