J Kim
J Kim

Reputation: 31

perl reference clarification needed

Straight from https://perldoc.perl.org/perlref.html

I don't understand below

 $$hashref{"KEY"}   = "VALUE";       # CASE 0
 ${$hashref}{"KEY"} = "VALUE";       # CASE 1
 ${$hashref{"KEY"}} = "VALUE";       # CASE 2
 ${$hashref->{"KEY"}} = "VALUE";     # CASE 3

What is the difference between case 1 and 2?

I am thinking anything inside ${} is a pointer to some address so it's like

my $hashref = \%hash;

${$hashref}{"KEY"} is really $$hashref{"KEY"} and this is dereferencing \%hash and looking up it's "KEY"

${$hashref->{"KEY"}} .. I would think is.. ?? I thought the rule was the bind closest to the left so I thought this also became $$hashref->{"KEY"}. which is same as ${$hashref}{'KEY'}. Am I getting this wrong?

Upvotes: 3

Views: 92

Answers (3)

zdim
zdim

Reputation: 66873

The difference between cases 0 and 1 is that in case 1 a block of code may be used inside ${}, which returns a hashref. Some things work without a {}, like the specific example in case 1, but some can't. It says elsewhere in perlref

Anywhere you'd put an identifier (or chain of identifiers) as part of a variable or subroutine name, you can replace the identifier with a simple scalar variable containing a reference of the correct type
...
Anything more complicated than a simple scalar variable must use methods 2 or 3 below.
...
Anywhere you'd put an identifier (or chain of identifiers) as part of a variable or subroutine name, you can replace the identifier with a BLOCK returning a reference of the correct type.

(emphasis mine)

An example

sub get_hr { return { a => 1, b => 2 } }

say ${ get_hr() }{a}

may go a bit overboard (and is unfit for production) but hopefully conveys it.

A lot of other clarifications are provided in the answers by amon and by ikegami.

Also see Using references in perlreftut and Caveats on precedence in perldsc

Upvotes: 0

ikegami
ikegami

Reputation: 385496

  • $NAME (e.g. $foo) is a scalar variable.
  • $BLOCK (e.g. ${ $ref }) is a scalar variable (via a reference).
  • $$NAME (e.g. $$ref) is short for ${ $NAME } (e.g. ${ $ref }).

Similarly,

  • $NAME{EXPR} (e.g. $foo{bar}) is a hash element.
  • $BLOCK{EXPR} (e.g. ${ $ref }{bar}) is a hash element (via a reference).
  • $$NAME{EXPR} (e.g. $$ref{bar}) is short for ${ $NAME }{EXPR} (e.g. ${ $ref }{bar}).

So,

  • $$hash_ref{"KEY"} is short for ${ $hashref }{"KEY"}
  • ${ $hash_ref }{"KEY"} is a hash element.
    $hashref is a reference to the hash.
  • ${ $hash{"KEY"} } is a scalar variable.
    $hash{"KEY"} is a reference to the scalar.
    %hash is a hash.
  • ${ $hash_ref->{"KEY"} } is a scalar variable.
    ($hash_ref->{"KEY"} is a nice way to write $$hash_ref{"KEY"}.)
    $hash_ref->{"KEY"} is a reference to the scalar.
    $hash_ref is a reference to a hash.

Upvotes: 0

amon
amon

Reputation: 57590

Case 0 and 1 are equivalent, these you have understood correctly.

Case 2 is a bit subtle:

${$hashref{"KEY"}} = "VALUE";

First, this executes $hashref{"KEY"} which looks up the "KEY" in a hash variable called %hashref. Despite its name it is a hash, not a hash reference! This returns a value in that hash.

Next, we dereference that value in the hash as a scalar reference: ${ ... }.

Finally, we assign a "VALUE" to the scalar reference target.

Case 3 is similar, but actually uses a hash reference.

If we rewrite Case 2 and 3, their relation might be clearer:

{ # Case 2
  my %hash;
  ${ $hash{"KEY"} } = "VALUE";
}

{ # Case 3
  my %hash;
  my $hashref = \%hash;
  ${ $hashref->{"KEY"} } = "VALUE";
}

Additional remarks:

  • The ${ … } dereference operator does not bind closest to left, it contains the value that will be dereferenced. The $$foo form is a short form of the ${ … } dereference operator if the reference is a normal scalar variable, as opposed to a more complex expression. This is not only the case for scalar references but also array refs (@{ … } and @$foo) and hash refs (%{ … } and %$foo).

  • The sigil ($ % @) of a dereference operator is not the type of the reference, but depends on whether we are accessing one or more values in the reference target.

    When we access a single value in a hash %hash this looks like $hash{"KEY"}.

    When we access a single value in a $hashref, this looks like $hashref->{"KEY"} or ${$hashref}{"KEY"} or $$hashref{"KEY"}.

    Despite the $ there is no scalar reference here. The scalar dereference operator ${ … } is essentially a separate operator from the hash reference subscript operator ${ … }{ … }.

  • The expression $$foo->{"KEY"} features a scalar reference to a hash reference! Firs the scalar reference $foo is dereferenced $$foo to a hash ref, in which a value …->{"KEY"} is accessed.

Upvotes: 1

Related Questions