Of course it should work, because $self is a reference. Although you copied the reference from @_ to $self, you didn't copy the hash that it refers to. So when you change something via the reference, you change the original hash.
If it's just a one-level hash, you could copy it like this:
my %copy = %{ $self };
# or
my $copy = { %{$self} };
If you want to copy a nested data structure, check out How do I print out or copy a recursive data structure? in the perlfaq. | [reply] [d/l] |
because ($self) = @_; makes a copy of the reference not a copy of the thing(s) the reference points at.
consider this
sub pass_var {
my ($foo,$bar) = @_;
print "foo: $foo bar: $bar\n";
$foo = 'c1';
$bar = 'c2';
print "changed: foo: $foo bar: $bar\n";
}
sub pass_ref {
my ($hash) = @_;
print "hash: $hash->{'key'}\n";
$hash->{'key'} = 'c1';
print "changed: hash: $hash->{'key'}\n";
print "hashref is: $hash\n";
}
my $hash;
my $foo;
my $bar;
$foo = 1;
$bar = 2;
$hash = {'key' => 1 };
&pass_var($foo,$bar);
print "after: foo: $foo bar: $bar\n";
&pass_ref($hash);
print "after: hash: $hash->{'key'}\n";
print "hashref is: $hash\n";
which yields this output
foo: 1 bar: 2
changed: foo: c1 bar: c2
after: foo: 1 bar: 2
hash: 1
changed: hash: c1
hashref is: HASH(0x80f86e0)
after: hash: c1
hashref is: HASH(0x80f86e0)
See how the hash both in and out of the sub point to the same memory address?
/\/\averick | [reply] [d/l] [select] |
One of the features of Perl is that the special variable @_ is actually an alias of the arguments passed to it. In other words, the following code may confuse people:
my $x = 3;
somesub ( $x );
sub somesub {
print ++$_[0];
}
print $x;
Because of the aliasing, &somesub actually alters the value of $x and both print statements print 4. However, with your second example, whatever you pass to &XXX must be a reference to an anonymous hash. When $self is assigned the value of $_[0], it is assigned the reference and thus can alter the underlying anonymous hash values. You can copy references all day long and they still point to the same thing (so long as you don't accidentally stringify them).
Cheers,
Ovid
Vote for paco!
Join the Perlmonks Setiathome Group or just click on the the link and check out our stats. | [reply] [d/l] |
If you pass in a hashref as the first argument, $_[0] refers to aliases that scalar. The lexically scoped copy produces a second hashref to the same external hash.
Some variations:
sub XXX {
my ($self) = @_;
$self->{age} = '17'; # does as you say
$_[0]->{'age'} = '21'; # a miraculous drivers license
$self = { %{$self} }; # now we have a copy of the innards
$self->{age} = '17'; # restoration of youth
# the world now thinks age=>21, we have private age=>17
# Youth will be lost when the sub exits
}
Hope that helps.
After Compline, Zaxo
Update: Ovid uses 'alias', and it's a better term for it. Less chance of confusion. | [reply] [d/l] [select] |
It isn't unusual to see something like my ($self) = @_;,
but I've found that using my $self = shift; is
more flexible. After all, if you need this in one function,
you need it in every one, so it is easy to cut-and-paste.
That being said, the reason you are able to modify "$self"
is because you are not really modifying it. You are modifying
the data that it "refers" to. It's a reference, which is
really like a pointer. It merely indicates where data is
stored, instead of actually storing data. This is why you
need to use the arrow operator to "dereference" it and
get the goods.
So, if you had code like:
sub X
{
my $self = shift;
$self->{age} = 17;
}
Then, as you expect, the 'age' value of your $self-referenced
object becomes 17. If you did something like this:
sub X
{
my $self = shift;
print "\$self = $self\n";
$self->{age} = 17;
print "\$self = $self\n";
}
You will note that $self does not change in the function,
and that in both cases it is clearly a reference to a HASH.
This is something different:
sub Z
{
my ($foo) = @_;
print "\$foo = $foo\n";
$foo = 17;
print "\$foo = $foo\n";
}
my $bar = 29;
print "\$bar = $bar\n";
Z($bar);
print "\$bar = $bar\n";
In this case, $bar is not modified, though a copy of it,
called $foo, is. Here's an example that uses a reference
instead:
sub Z
{
my ($foo) = @_;
print "\$foo = $foo\n";
$$foo = 17;
print "\$foo = $foo\n";
}
my $bar = 29;
print "\$bar = $bar\n";
Z(\$bar);
print "\$bar = $bar\n";
On the way into the function, the variable is prefixed with
a backslash, meaning "pass by reference". Inside the
function, the scalar is "used" with a second $, meaning
that you are modifying the value, not the reference. This
is another form of dereferencing, not unlike the "arrow
operator" used by arrays and hashes.
Any time you see an arrow operator, think of it like a
pointer, which it is supposed to represent visually. It
points to something which is elsewhere. | [reply] [d/l] [select] |