Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dereferencing in case of $_[0], $_[1] ..... so on

Tags:

perl

please see the below code:

$scalar = 10;

subroutine(\$scalar);

sub subroutine {
    my $subroutine_scalar = ${$_[0]}; #note you need the {} brackets, or this doesn't work!
    print "$subroutine_scalar\n";
}

In the code above you can see the comment written "note you need the {} brackets, or this doesn't work!" . Please explain the reason that why we cant use the same statement as:

my $subroutine_scalar = $$_[0];

i.e. without using the curly brackets.

like image 271
Abhishek Verma Avatar asked Oct 18 '13 11:10

Abhishek Verma


3 Answers

Many people have already given correct answers here. I wanted to add an example I found illuminating. You can read the documentation in perldoc perlref for more information.

Your problem is one of ambiguity, you have two operations $$ and [0] working on the same identifier _, and the result depends on which operation is performed first. We can make it less ambiguous by using the support curly braces ${ ... }. $$_[0] could (for a human anyway) possibly mean:

  • ${$$_}[0] -- dereference the scalar $_, then take its first element.
  • ${$_[0]} -- take element 0 of the array @_ and dereference it.

As you can see, these two cases refer to completely different variables, @_ and $_.

Of course, for Perl it is not ambiguous, we simply get the first option, since dereferencing is performed before key lookup. We need the support curly braces to override this dereferencing, and that is why your example does not "work" without support braces.

You might consider a slightly less confusing functionality for your subroutine. Instead of trying to do two things at once (get the argument and dereference it), you can do it in two stages:

sub foo {
    my $n = shift;
    print $$n;
}

Here, we take the first argument off @_ with shift, and then dereference it. Clean and simple.

Most often, you will not be using references to scalar variables, however. And in those cases, you can make use of the arrow operator ->

my @array = (1,2,3);
foo(\@array);

sub foo {
    my $aref = shift;
    print $aref->[0];
}

I find using the arrow operator to be preferable to the $$ syntax.

like image 191
TLP Avatar answered Nov 11 '22 13:11

TLP


${ $x }[0] grabs the value of element 0 in the array referenced by $x.

${ $x[0] } grabs the value of scalar referenced by the element 0 of the array @x.

>perl -E"$x=['def']; @x=\'abc'; say ${ $x }[0];"
def

>perl -E"$x=['def']; @x=\'abc'; say ${ $x[0] };"
abc

$$x[0] is short for ${ $x }[0].

>perl -E"$x=['def']; @x=\'abc'; say $$x[0];"
def
like image 38
ikegami Avatar answered Nov 11 '22 14:11

ikegami


my $subroutine_scalar = $$_[0];

is same as

my $subroutine_scalar = $_->[0]; # $_ is array reference

On the other hand,

my $subroutine_scalar = ${$_[0]};

dereferences scalar ref for first element of @_ array, and can be written as

my ($sref) = @_;
my $subroutine_scalar = ${$sref}; # or $$sref for short
like image 42
mpapec Avatar answered Nov 11 '22 12:11

mpapec