I'm not going to go into much detail here; I've knocked up a lil example application to show where I'm having trouble; I'd like to know why $REF_DREF_A != $REF_DREF_B (and equally why there isn't a "hippo" qualifier to the "hello" in @DREF_B)...

But more importantly, can I easily make them the same, without wrapping "the array" in an object? I want to dereference the array (and still use it like an array), not clone it.

INPUT:

#!/usr/bin/perl
my(@array) = ();
push(@array,"hello");
my($REF_A) = \@array;
my($REF_B) = \@array;
print "contents of source array:\n\n";
print @array;
print "\n\nreferences to the source array:\n\n";
print "A: ".$REF_A." B: ".$REF_B;
my(@DREF_A) = @$REF_A;
my(@DREF_B) = @$REF_B;
push(@DREF_A,"hippos");
print "\n\ncontents of A dereferenced source array:\n\n";
print @DREF_A;
print "\n\ncontents of B dereferenced source array:\n\n";
print @DREF_B;
my($REF_DREF_A) = \@DREF_A;
my($REF_DREF_B) = \@DREF_B;
print "\n\nre-references to the source array:\n\n";
print "A: ".$REF_DREF_A." B: ".$REF_DREF_B;
print "\n\n";

OUTPUT:

contents of source array:
hello
references to the source array:
A: ARRAY(0x35fb0) B: ARRAY(0x35fb0)
contents of A dereferenced source array:
hellohippos
contents of B dereferenced source array:
hello
re-references to the source array:
A: ARRAY(0x1831e90) B: ARRAY(0x1831ec0)
Press any key to continue . . .

you don't need to make a copy of the array referenced by a reference to use it. But you need to make a copy if you don't want the original variable the reference points to to be affected.

I'd like to know why $REF_DREF_A != $REF_DREF_B

because they are references to two different arrays:

my(@DREF_A) = @$REF_A;
my(@DREF_B) = @$REF_B;

my($REF_DREF_A) = \@DREF_A;
my($REF_DREF_B) = \@DREF_B;

@DREF_A and @DREF_B are two seperate variables even though they are two copies of the same data. So $REF_DREF_A and $REF_DREF_B are pointer to two seperate bits of data.

Hmm, I have ended up wrapping the array in an object for now.. My actual project is somewhat more advanced than that example; I need to be able to manipulate a number of arrays from many different "angles" without defining any kind of notification..

I can get READ access to the array without derefencing it, but write access (even by explicit index) doesn't seem to work for me without doing something like this:

my(@array) = ();
$self->{arrayref} = \@array;
 
[B]then sometime later...[/B]
 
my($REF) = $self->{arrayref};
my(@array) = @{$REF};
push(@array,$data);
$self->{arrayref} = \@array;

That's pretty much what the object I'm using at the moment does at every access... Is this really the best way to go about it? Because it seems like there's an amount of uneccessary garbage being generated behind the scenes.

I suppose, anything I do is going to have a similar overhead; it's always going to be neccessary to re-allocate sequential space to the array when the size changes..

I'm used to silence/seamlessness when using array references.

Maybe I'll use chained objects or psuedo-fixed-length arrays if it turns into a problem.. It's good to have an encapsulated array just-in-case

you should be able to do something like this:

my $self = {};
my @array = qw(Mary had a little);
$self->{arrayref} = \@array;
push @{$self->{arrayref}},'lamb';#append new element  to array
print join(' ',@{$self->{arrayref}});
print "\n";
$self->{arrayref}->[0] = 'Joe';#change index 0 of array
print join(' ',@{$self->{arrayref}});

That's good; thanks for that, it works as I'd expect it to.

However, going back to my example...

If this:

my(@DREF_A) = @$REF_A;
my(@DREF_B) = @$REF_B;
push(@DREF_A,"hippos");

Is changed to this:

my(@DREF_A) = @$REF_A;
push(@DREF_A,"hippos");
my(@DREF_B) = @$REF_B;

Shouldn't that change the contents of @DREF_B? (The data should now be copied after the array is changed) It doesn't though, I've just checked it (same output as before).

Also, the @DREF_B output doesn't match the @DREF_A output even if both @DREF_A and @DREF_B are sourced from the same pointer, as in:

my(@DREF_A) = @$REF_A;
push(@DREF_A,"hippos");
my(@DREF_B) = @$REF_A;

Although it does work as per your example:

push(@$REF_A,"hippos");
my(@DREF_A) = @$REF_A;
my(@DREF_B) = @$REF_B;

Seems strange though! Shouldn't @$REF_A evaluate to the same thing whether its a subroutine parameter or a variable assignment?

That's good; thanks for that, it works as I'd expect it to.

However, going back to my example...

If this:

my(@DREF_A) = @$REF_A;
my(@DREF_B) = @$REF_B;
push(@DREF_A,"hippos");

Is changed to this:

my(@DREF_A) = @$REF_A;
push(@DREF_A,"hippos");
my(@DREF_B) = @$REF_B;

Shouldn't that change the contents of @DREF_B? (The data should now be copied after the array is changed) It doesn't though, I've just checked it (same output as before)

No. @DREF_A and @DREF_B are copies of whatever reference you dereferenced at that point. They are entirely seperate from the original data at that point.

Also, the @DREF_B output doesn't match the @DREF_A output even if both @DREF_A and @DREF_B are sourced from the same pointer, as in:

my(@DREF_A) = @$REF_A;
push(@DREF_A,"hippos");
my(@DREF_B) = @$REF_A;

Same reason. @DREF_A has no connection to $REF_A anymore. @DREF_B will have the value of $REF_A. You did not make any changes to $REF_A, you made a copy of it and changed the value of the copy (@DREF_A)'

Although it does work as per your example:

push(@$REF_A,"hippos");
my(@DREF_A) = @$REF_A;
my(@DREF_B) = @$REF_B;

Seems strange though! Shouldn't @$REF_A evaluate to the same thing whether its a subroutine parameter or a variable assignment?

In the above you changed the value of the original data that $REF_A points to. Then you make two new copies which will both have the same value because $REF_A and $REF_B are pointers to the same data.

:)

Comments
Good comments & valuable insight; thanks!
This article has been dead for over six months. Start a new discussion instead.