Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: How do you dereference an array without creating a copy of the array?

When I dereference an array using @$arrayRef or @{$arrayRef} it appears to create a copy of the array. Is there a correct way to dereference an array?

This code...

sub updateArray1 {
        my $aRef = shift;
        my @a = @$aRef;
        my $aRef2 = \@a;

        $a[0] = 0;
        push(@a, 3);
        my $aRef3 = \@a;

        print "inside1 \@a: @a\n";
        print "inside1 \$aRef: $aRef\n";
        print "inside1 \$aRef2: $aRef2\n";
        print "inside1 \$aRef3: $aRef3\n\n";
}

my @array = (1, 2);

print "before: @array\n";
my $ar = \@array;
print "before: $ar\n\n";

updateArray1(\@array);

print "after: @array\n";
$ar = \@array;
print "after: $ar\n\n";

... has the output...

before: 1 2
before: ARRAY(0x1601440)

inside1 @a: 0 2 3
inside1 $aRef: ARRAY(0x1601440)
inside1 $aRef2: ARRAY(0x30c1f08)
inside1 $aRef3: ARRAY(0x30c1f08)

after: 1 2
after: ARRAY(0x1601440)

As you can see, @$aRef creates a new pointer address.

The only way I've found to get around this is to only use the reference:

sub updateArray2 {
        my $aRef = shift;

        @$aRef[0] = 0;
        push(@$aRef, 3);

        print "inside2 \@\$aRef: @$aRef\n";
        print "inside2 \$aRef: $aRef\n\n";
}

updateArray2(\@array);

print "after2: @array\n";
$ar = \@array;
print "after2: $ar\n\n";

Which produces the output:

inside2 @$aRef: 0 2 3
inside2 $aRef: ARRAY(0x1601440)

after2: 0 2 3
after2: ARRAY(0x1601440)

Is it possible to dereference a pointer to an array without the whole array getting duplicated? Or do I need to keep it in reference form and dereference it any time I want to use it?

like image 268
DemiImp Avatar asked Jul 23 '17 06:07

DemiImp


People also ask

How do I dereference an array in Perl?

Dereferencing an array It is done by placing the @ symbol (the sigil representing arrays) in-front of the reference. This can be written either wrapped in curly braces: @{$names_ref} or without the curly braces: @$names_ref.

How do you dereference an array?

You cannot dereference an array, only a pointer. What's happening here is that an expression of array type, in most contexts, is implicitly converted to ("decays" to) a pointer to the first element of the array object. So ar "decays" to &ar[0] ; dereferencing that gives you the value of ar[0] , which is an int .

What is Dereferencing in Perl?

Dereferencing in Perl returns the value from a reference point to the location. To dereference a reference simply use $, @ or % as a prefix of the reference variable depending on whether the reference is pointing to a scalar, array, or hash.

Which of the following operator dereference a variable in Perl?

In order to dereference, we use the prefix $, @, % or & depending on the type of the variable(a reference can point to a array, scalar, or hash etc).


2 Answers

Dereferencing does not create a copy as can be seen in the following example:

my @a = qw(a b c);
my $ra = \@a;
@{$ra}[0,1] = qw(foo bar);  # dereferencing is done here but not copying
print @$ra; # foo bar c
print @a; # foo bar c

Instead, assigning the (dereferenced) array to another array creates the copy:

my @a = qw(a b c);
my $ra = \@a;
my @newa = @$ra;   # copy by assigning
$newa[0] = 'foo';
print @newa; # foo b c
print @a; # a b c

Assigning one array to another says essentially that all elements from the old array should be assigned to the new array too - which is different from just having a different name for the original array. But assigning one array reference to another just makes the old array available with a different name, i.e. copy array reference vs. copy array content.

Note that this seems to be different to languages like Python or Java because in these languages variables describe array objects only, i.e. the reference to the array and not the content of the array.

like image 110
Steffen Ullrich Avatar answered Nov 15 '22 07:11

Steffen Ullrich


Using the experimental refaliasing feature:

use 5.022;
use warnings;
use feature 'refaliasing';
no warnings 'experimental::refaliasing';
\my @array = $array_ref;

But why not just keep it as a reference? There's nothing you can do with an array that you can't also do with an array reference.

like image 21
ysth Avatar answered Nov 15 '22 07:11

ysth